better help

Summary:
- make sure former options of `./infer/lib/python/infer.py --help`, `./infer/lib/python/infer.py --help -- make`, ... all appear in `infer --help`
- add some options to config.ml and infer.ml to fix missing options
- have `infer --help` output help info for Toplevel + Backend + Clang + Java
- wrap help lines at 80 characters

Reviewed By: jberdine

Differential Revision: D3669865

fbshipit-source-id: 1ceff2d
master
Jules Villard 9 years ago committed by Facebook Github Bot 6
parent 894e92d4f3
commit cdce8f9794

@ -29,6 +29,8 @@ let exes = [
("infer", Toplevel);
]
let all_exes = IList.map snd exes
let current_exe =
try IList.assoc string_equal (Filename.basename Sys.executable_name) exes
with Not_found -> Toplevel
@ -89,21 +91,84 @@ let xdesc {long; short; spec; doc} =
in
(key long short, xspec long spec, doc)
let pad_and_xform left_width desc =
let wrap_line indent_string wrap_length line =
let indent_length = String.length indent_string in
let word_sep = " " in
let words = Str.split (Str.regexp_string word_sep) line in
let add_word_to_paragraph (rev_lines, non_empty, line, line_length) word =
let word_length = String.length word in
let new_length = line_length + (String.length word_sep) + word_length in
let new_non_empty = non_empty || word <> "" in
if new_length > wrap_length && non_empty then
(line::rev_lines, true, indent_string ^ word, indent_length + word_length)
else
let sep = if line_length = indent_length then "" else word_sep in
let new_line = line ^ sep ^ word in
if new_length > wrap_length && new_non_empty then
(new_line::rev_lines, false, indent_string, indent_length)
else
(rev_lines, new_non_empty, new_line, String.length new_line) in
let (rev_lines, _, line, _) = IList.fold_left add_word_to_paragraph ([], false, "", 0) words in
IList.rev (line::rev_lines)
let pad_and_xform doc_width left_width desc =
match desc with
| {doc = ""} ->
xdesc desc
| {long; doc} ->
let short_meta = short_meta desc in
let gap = left_width - (left_length long short_meta) in
if gap < 0 then
xdesc {desc with doc = short_meta ^ "\n" ^ (String.make (4 + left_width) ' ') ^ doc}
else
xdesc {desc with doc = short_meta ^ (String.make (gap + 1) ' ') ^ doc}
let align ?(limit=max_int) desc_list =
let left_width = IList.fold_left (max_left_length limit) 0 desc_list in
(IList.map (pad_and_xform left_width) desc_list)
let indent_doc doc =
(* 2 blank columns before option + 2 columns of gap between flag and doc *)
let left_indent = 4 + left_width in
(* align every line after the first one of [doc] *)
let doc = Str.global_replace (Str.regexp_string "\n")
("\n" ^ String.make left_indent ' ') doc in
(* align the first line of [doc] *)
let short_meta = short_meta desc in
let gap = left_width - (left_length long short_meta) in
if gap < 0 then
short_meta ^ "\n" ^ (String.make left_indent ' ') ^ doc
else
short_meta ^ (String.make (gap + 1) ' ') ^ doc
in
let wrapped_lines =
let lines = Str.split (Str.regexp_string "\n") doc in
let wrap_line s =
if String.length s > doc_width then
wrap_line "" doc_width s
else [s] in
IList.map wrap_line lines in
let doc = indent_doc (String.concat "\n" (IList.flatten wrapped_lines)) in
xdesc {desc with doc}
let align desc_list =
let min_term_width = 80 in
(* Try to prevent `tput` from complaining about $TERM not being set as it pollutes stderr. We
cannot redirect stderr as `tput` needs access to the tty and we are already redirecting stdout
to read the result from `tput`. *)
(try Unix.getenv "TERM" |> ignore
with Not_found -> Unix.putenv "TERM" "ansi");
let cur_term_width = try int_of_string (with_process_in "tput cols" input_line)
with
| End_of_file (* tput is unhappy *)
| Failure "int_of_string" (* not sure if possible *) -> min_term_width in
(* 2 blank columns before option + 2 columns of gap between flag and doc *)
let extra_space = 4 in
let min_left_width = 15 in
let max_left_width = 49 in
let doc_width term_width left_width = term_width - extra_space - left_width in
let term_width doc_width left_width = left_width + extra_space + doc_width in
let max_doc_width = 100 in
let max_term_width = term_width max_left_width max_doc_width in
(* how many columns to reserve for the option names *)
let left_width =
let opt_left_width = IList.fold_left (max_left_length max_left_width) 0 desc_list in
let (--) a b = float_of_int a -. float_of_int b in
let multiplier = (max_left_width -- min_left_width) /. (max_term_width -- min_term_width) in
(* at 80 columns use min_left_width then use extra columns until opt_left_width *)
let cols_after_min_width = float_of_int (max 0 (cur_term_width - min_term_width)) in
min (int_of_float (cols_after_min_width *. multiplier) + min_left_width) opt_left_width in
let doc_width = min max_doc_width (doc_width cur_term_width left_width) in
(IList.map (pad_and_xform doc_width left_width) desc_list)
let check_no_duplicates desc_list =
@ -398,6 +463,8 @@ let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var exe_u
Arg.usage !full_speclist usage_msg ;
exit status
in
(* "-help" and "--help" are automatically recognized by Arg.parse, so we have to give them special
treatment *)
let add_or_suppress_help speclist =
let unknown opt =
(opt, Arg.Unit (fun () -> raise (Arg.Bad ("unknown option '" ^ opt ^ "'"))), "") in
@ -417,27 +484,59 @@ let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var exe_u
in
let normalize speclist =
let norm k =
let len = String.length k in
if len > 3 && String.sub k 0 3 = "no-" then String.sub k 3 (len - 3) else k in
let remove_no s =
let len = String.length k in
if len > 3 && String.sub s 0 3 = "no-" then String.sub s 3 (len - 3) else s in
let remove_weird_chars = Str.global_replace (Str.regexp "[^a-z0-9-]") "" in
remove_weird_chars @@ String.lowercase @@ remove_no k in
let compare_specs {long = x} {long = y} =
match x, y with
| "--", "--" -> 0
| "--", _ -> 1
| _, "--" -> -1
| _ -> String.compare (norm x) (norm y) in
| _ ->
let lower_norm s = String.lowercase @@ norm s in
String.compare (lower_norm x) (lower_norm y) in
let sort speclist = IList.sort compare_specs speclist in
add_or_suppress_help (align ~limit:46 (sort speclist))
align (sort speclist)
in
let curr_desc_list = IList.assoc ( = ) current_exe exe_desc_lists
let add_to_curr_speclist ?header exe =
let mk_header_spec heading =
("", Arg.Unit (fun () -> ()), "\n " ^ heading ^ "\n") in
let exe_descs = IList.assoc ( = ) exe exe_desc_lists in
let exe_speclist = normalize !exe_descs in
(* Return false if the same option appears in [speclist], unless [doc] is non-empty and the
documentation in [speclist] is empty. The goal is to keep only one instance of each option,
and that instance is the one that has a non-empty docstring if there is one. *)
let is_not_dup_with_doc speclist (opt, _, doc) =
opt = "" ||
IList.for_all (fun (opt', _, doc') ->
(doc <> "" && doc' = "") || (not (string_equal opt opt'))) speclist in
let unique_exe_speclist = IList.filter (is_not_dup_with_doc !curr_speclist) exe_speclist in
curr_speclist := IList.filter (is_not_dup_with_doc unique_exe_speclist) !curr_speclist @
(match header with
| Some s -> mk_header_spec s:: unique_exe_speclist
| None -> unique_exe_speclist)
in
(* curr_speclist includes args for current exe with docs, and all other args without docs, so
(* speclist includes args for current exe with docs, and all other args without docs, so
that all args can be parsed, but --help and parse failures only show external args for
current exe *)
curr_speclist := normalize !curr_desc_list
if current_exe = Toplevel then
add_to_curr_speclist ~header:"Toplevel options" current_exe
else
add_to_curr_speclist current_exe
;
curr_speclist := add_or_suppress_help !curr_speclist
;
if current_exe = Toplevel then (
add_to_curr_speclist ~header:"Analysis (backend) options" Analyze;
add_to_curr_speclist ~header:"Clang frontend options" Clang;
add_to_curr_speclist ~header:"Java frontend options" Java;
)
;
assert( check_no_duplicates !curr_speclist )
;
full_speclist := normalize !full_desc_list
full_speclist := add_or_suppress_help (normalize !full_desc_list)
;
let env_args = decode_env_to_argv (try Unix.getenv env_var with Not_found -> "") in
(* begin transitional support for INFERCLANG_ARGS *)

@ -15,6 +15,8 @@ type exe = Analyze | Clang | Java | Llvm | Print | StatsAggregator | Toplevel
val current_exe : exe
val all_exes : exe list
(** The [mk_*] functions declare command line options, while [parse] parses then according to the
declared options.

@ -380,7 +380,7 @@ let resolve path =
let inferconfig_home =
CLOpt.mk_string_opt ~deprecated:["inferconfig_home"] ~long:"inferconfig-home"
~exes:CLOpt.[Analyze] ~meta:"dir" "Path to the .inferconfig file"
~exes:CLOpt.all_exes ~meta:"dir" "Path to the .inferconfig file"
and project_root =
CLOpt.mk_string_opt ~deprecated:["project_root"; "-project_root"] ~long:"project-root" ~short:"pr"
@ -440,33 +440,26 @@ and rest =
and absolute_paths =
CLOpt.mk_bool ~long:"absolute-paths"
~exes:CLOpt.[Toplevel] "Report errors using absolute paths"
~exes:CLOpt.[Java] "Report errors using absolute paths"
(** Flag for abstracting fields of structs
0 = no
1 = forget some fields during matching (and so lseg abstraction) *)
and abs_struct =
CLOpt.mk_int ~deprecated:["absstruct"] ~long:"abs-struct" ~default:1
~meta:"int" "Specify abstraction level for fields of structs"
~meta:"int" "Specify abstraction level for fields of structs:\n\
- 0 = no\n\
- 1 = forget some fields during matching (and so lseg abstraction)"
(** Flag for abstracting numerical values
0 = no abstraction.
1 = evaluate all expressions abstractly.
2 = 1 + abstract constant integer values during join.
*)
and abs_val =
CLOpt.mk_int ~deprecated:["absval"] ~long:"abs-val" ~default:2
~meta:"int" "Specify abstraction level for expressions"
~meta:"int" "Specify abstraction level for expressions:\n\
- 0 = no abstraction\n\
- 1 = evaluate all expressions abstractly\n\
- 2 = 1 + abstract constant integer values during join"
(** Flag for forgetting memory leak
false = no
true = forget leaked memory cells during abstraction
*)
and allow_leak =
CLOpt.mk_bool ~deprecated:["leak"] ~long:"allow-leak"
"Forget leaks during abstraction"
"Forget leaked memory during abstraction"
(** Whether specs can be cleaned up before starting analysis *)
and allow_specs_cleanup =
CLOpt.mk_bool ~deprecated:["allow_specs_cleanup"] ~long:"allow-specs-cleanup"
"Allow to remove existing specs before running analysis when it's not incremental"
@ -481,26 +474,33 @@ and (
let long = Printf.sprintf "%s-%s" analyzer_name suffix in
let deprecated =
IList.map (Printf.sprintf "%s_%s" analyzer_name) deprecated_suffix in
let help_string = Printf.sprintf "%s (%s only)" help analyzer_name in
CLOpt.mk_string_list ~deprecated ~long ~exes:CLOpt.[Analyze] ~meta help_string in
(* empty doc to hide the options from --help since there are many redundant ones *)
CLOpt.mk_string_list ~deprecated ~long ~meta "" in
ignore (
let long = "<analyzer>-" ^ suffix in
CLOpt.mk_string_list ~long ~meta ~f:(fun _ -> raise (Arg.Bad "invalid option"))
~exes:CLOpt.[Toplevel;Print]
help
);
IList.map (fun (name, analyzer) -> (analyzer, mk_option name)) string_to_analyzer in
(
mk_filtering_options
~suffix:"blacklist-files-containing"
~deprecated_suffix:["blacklist_files_containing"]
~help:"blacklist files containing the specified string"
~help:"blacklist files containing the specified string for the given analyzer (see \
--analyzer for valid values)"
~meta:"string",
mk_filtering_options
~suffix:"blacklist-path-regex"
~deprecated_suffix:["blacklist"]
~help:"blacklist the analysis of files whose relative path matches the specified OCaml-style \
regex"
regex\n\
(to whitelist: --<analyzer>-whitelist-path-regex)"
~meta:"path regex",
mk_filtering_options
~suffix:"whitelist-path-regex"
~deprecated_suffix:["whitelist"]
~help:"whitelist the analysis of files whose relative path matches the specified OCaml-style \
regex"
~help:""
~meta:"path regex",
mk_filtering_options
~suffix:"suppress-errors"
@ -508,80 +508,88 @@ and (
~help:"do not report a type of errors"
~meta:"error name")
(** Check whether to report Analysis_stops message in user mode *)
and analysis_stops =
CLOpt.mk_bool ~deprecated:["analysis_stops"] ~long:"analysis-stops"
"Issue a warning when the analysis stops"
(** Setup the analyzer in order to filter out errors for this analyzer only *)
and analyzer =
let () = match Infer with
(* NOTE: if compilation fails here, it means you have added a new analyzer without updating the
documentation of this option *)
| Capture | Compile | Infer | Eradicate | Checkers | Tracing | Crashcontext -> () in
CLOpt.mk_symbol_opt ~deprecated:["analyzer"] ~long:"analyzer" ~short:"a"
"Specify the analyzer for the path filtering"
~exes:CLOpt.[Toplevel]
"Specify which analyzer to run (only one at a time is supported):\n\
- infer, eradicate, checkers: run the specified analysis\n\
- capture: run capture phase only (no analysis)\n\
- compile: run compilation command without interfering (Java only)\n\
- crashcontext, tracing: experimental (see --crashcontext and --tracing)"
~symbols:string_to_analyzer
and android_harness =
CLOpt.mk_bool ~deprecated:["harness"] ~long:"android-harness"
"Create harness to detect bugs involving the Android lifecycle"
~exes:CLOpt.[Java]
"(Experimental) Create harness to detect issues involving the Android lifecycle"
(** if true, completely ignore the possibility that errors can be caused by unknown procedures
during the symbolic execution phase *)
and angelic_execution =
CLOpt.mk_bool ~deprecated:["angelic_execution"] ~long:"angelic-execution" ~default:true
"Angelic execution, where the analysis ignores errors caused by unknown procedure calls"
(** Flag for ignoring arrays and pointer arithmetic.
0 = treats both features soundly.
1 = assumes that the size of every array is infinite.
2 = assumes that all heap dereferences via array indexing and pointer arithmetic are correct.
*)
and array_level =
CLOpt.mk_int ~deprecated:["arraylevel"] ~long:"array-level" ~default:0
~meta:"int" "Level of treating the array indexing and pointer arithmetic"
~meta:"int" "Level of treating the array indexing and pointer arithmetic:\n\
- 0 = treats both features soundly\n\
- 1 = assumes that the size of every array is infinite\n\
- 2 = assumes that all heap dereferences via array indexing and pointer \
arithmetic are correct"
and ast_file =
CLOpt.mk_string_opt ~long:"ast-file" ~short:"ast"
~meta:"file" "AST file for the translation"
and blacklist =
CLOpt.mk_string_opt ~deprecated:["-blacklist-regex"] ~long:"blacklist"
~meta:"regex" "Skip analysis of files matched by the specified regular expression"
CLOpt.mk_string_opt ~deprecated:["-blacklist-regex";"-blacklist"] ~long:"buck-blacklist"
~exes:CLOpt.[Toplevel]
~meta:"regex" "Skip analysis of files matched by the specified regular expression (Buck \
flavors only)"
(** Automatically set when running from within Buck *)
and buck =
CLOpt.mk_bool ~long:"buck"
"To use when run with buck"
""
and buck_build_args =
CLOpt.mk_string_list ~long:"Xbuck"
"Pass values as command-line arguments to invocations of `buck build`"
~exes:CLOpt.[Toplevel]
"Pass values as command-line arguments to invocations of `buck build` (Buck flavors only)"
and buck_out =
CLOpt.mk_string_opt ~long:"buck-out"
~exes:CLOpt.[StatsAggregator] ~meta:"dir" "Specify the root directory of buck-out"
(** Outfile to save bugs stats in csv format *)
and bugs_csv =
CLOpt.mk_option ~deprecated:["bugs"] ~long:"bugs-csv" ~f:create_outfile
~meta:"bugs.csv" "Create file bugs.csv containing a list of bugs in CSV format"
CLOpt.mk_option ~deprecated:["bugs"] ~long:"issues-csv" ~f:create_outfile
~exes:CLOpt.[Print]
~meta:"file" "Create a file containing a list of issues in CSV format"
(** Outfile to save bugs stats in json format *)
and bugs_json =
CLOpt.mk_option ~deprecated:["bugs_json"] ~long:"bugs-json" ~f:create_outfile
~meta:"bugs.json" "Create file bugs.json containing a list of bugs in JSON format"
CLOpt.mk_option ~deprecated:["bugs_json"] ~long:"issues-json" ~f:create_outfile
~exes:CLOpt.[Print]
~meta:"file" "Create a file containing a list of issues in JSON format"
(** Outfile to save bugs stats in txt format *)
and bugs_txt =
CLOpt.mk_option ~deprecated:["bugs_txt"] ~long:"bugs-txt" ~f:create_outfile
~meta:"bugs.txt" "Create file bugs.txt containing a list of bugs in TXT format"
CLOpt.mk_option ~deprecated:["bugs_txt"] ~long:"issues-txt" ~f:create_outfile
~exes:CLOpt.[Print]
~meta:"file" "Create a file containing a list of issues in TXT format"
(** Outfile to save bugs stats in xml format *)
and bugs_xml =
CLOpt.mk_option ~deprecated:["bugs_xml"] ~long:"bugs-xml" ~f:create_outfile
~meta:"bugs.xml" "Create file bugs.xml containing a list of bugs in XML format"
CLOpt.mk_option ~deprecated:["bugs_xml"] ~long:"issues-xml" ~f:create_outfile
~exes:CLOpt.[Print]
~meta:"file" "Create a file containing a list of issues in XML format"
(** Outfile to save call stats in csv format *)
and calls_csv =
CLOpt.mk_option ~deprecated:["calls"] ~long:"calls-csv" ~f:create_outfile
~meta:"calls.csv" "Write individual calls in csv format to calls.csv"
~exes:CLOpt.[Print]
~meta:"file" "Write individual calls in csv format to a file"
and changed_files_index =
CLOpt.mk_string_opt ~long:"changed-files-index" ~exes:CLOpt.[Toplevel] ~meta:"file"
@ -603,7 +611,6 @@ and _ =
CLOpt.mk_string_opt ~deprecated:["classpath"] ~long:"classpath"
~meta:"path" "Specify where to find user class files and annotation processors"
(** optional command-line name of the .cluster file *)
and cluster =
CLOpt.mk_string_opt ~deprecated:["cluster"] ~long:"cluster"
~meta:"file" "Specify a .cluster file to be analyzed"
@ -616,20 +623,23 @@ and code_query =
If a procedure was changed beforehand, keep the changed marking. *)
and continue =
CLOpt.mk_bool ~deprecated:["continue"] ~long:"continue"
"Continue the capture for the reactive analysis,\
increasing the changed files/procedures."
~exes:CLOpt.[Toplevel]
"Continue the capture for the reactive analysis, increasing the changed files/procedures. (If \
a procedure was changed beforehand, keep the changed marking.)"
and copy_propagation =
CLOpt.mk_bool ~deprecated:["copy-propagation"] ~long:"copy-propagation"
"Perform copy-propagation on the IR"
(** Set language to Java *)
and curr_language =
let var = ref Clang in
CLOpt.mk_set var Java ~deprecated:["java"] ~long:"java" "Set language to Java" ;
CLOpt.mk_set var Java ~deprecated:["java"] ~long:"java" "";
var
and cxx_experimental =
CLOpt.mk_bool ~deprecated:["cxx-experimental"] ~long:"cxx"
~exes:CLOpt.[Clang]
"Analyze C++ methods, still experimental"
and debug, print_types, write_dotty =
@ -639,10 +649,11 @@ and debug, print_types, write_dotty =
"Print types in symbolic heaps"
and write_dotty =
CLOpt.mk_bool ~deprecated:["dotty"] ~long:"write-dotty"
"Produce dotty files in the results directory"
"Produce dotty files for specs in the results directory"
in
let debug =
CLOpt.mk_bool_group ~deprecated:["debug"] ~long:"debug" ~short:"g"
~exes:CLOpt.[Analyze]
"Debug mode (also sets --print-types and --write-dotty)"
[print_types; write_dotty]
in
@ -650,113 +661,126 @@ and debug, print_types, write_dotty =
and debug_exceptions =
CLOpt.mk_bool ~long:"debug-exceptions"
~exes:CLOpt.[Analyze]
"Generate lightweight debugging information: just print the internal exceptions during analysis"
(* The classes in the given jar file will be translated. No sources needed *)
and dependencies =
CLOpt.mk_bool ~deprecated:["dependencies"] ~long:"dependencies"
"Translate all the dependencies during the capture"
"Translate all the dependencies during the capture. The classes in the given jar file will be \
translated. No sources needed."
(** If true shows internal exceptions*)
and developer_mode =
CLOpt.mk_bool ~deprecated:["developer_mode"] ~long:"developer-mode"
~default:(CLOpt.current_exe = CLOpt.Print)
"Reserved"
"Show internal exceptions"
and disable_checks =
CLOpt.mk_string_list ~deprecated:["disable_checks"] ~long:"disable-checks" ~meta:"error name"
"do not show reports coming from this type of errors"
~exes:CLOpt.[Toplevel;Print]
"Do not show reports coming from this type of errors"
(** if true, print cfg nodes in the dot file that are not defined in that file *)
and dotty_cfg_libs =
CLOpt.mk_bool ~deprecated:["dotty_no_cfg_libs"] ~long:"dotty-cfg-libs" ~default:true
"Prints the cfg of the code coming from the libraries"
"Print the cfg of the code coming from the libraries"
and enable_checks =
CLOpt.mk_string_list ~deprecated:["enable_checks"] ~long:"enable-checks" ~meta:"error name"
"show reports coming from this type of errors"
"Show reports coming from this type of errors"
(** command line option to activate the eradicate checker. *)
and checkers, eradicate, crashcontext =
(* Run only the checkers instead of the full analysis *)
let checkers =
CLOpt.mk_bool ~deprecated:["checkers"] ~long:"checkers"
"Run only the checkers instead of the full analysis"
""
in
(* Activate the eradicate checker for java annotations (also sets --checkers) *)
let eradicate =
CLOpt.mk_bool_group ~deprecated:["eradicate"] ~long:"eradicate"
"Activate the eradicate checker for java annotations (also sets --checkers)"
""
[checkers]
in
(* Activate the crashcontext checker for java stack trace context reconstruction *)
let crashcontext =
CLOpt.mk_bool_group ~deprecated:["crashcontext"] ~long:"crashcontext"
"Activate the crashcontext checker for java stack trace context \
reconstruction (also sets --checkers)"
""
[checkers]
in
(checkers, eradicate, crashcontext)
(* Use file for the err channel *)
and err_file =
CLOpt.mk_string ~deprecated:["err_file"] ~long:"err-file" ~default:""
~exes:CLOpt.[Analyze] ~meta:"file" "use file for the err channel"
~meta:"file" ""
and fail_on_bug =
CLOpt.mk_bool ~deprecated:["-fail-on-bug"] ~long:"fail-on-issue" ~default:false
~exes:CLOpt.[Toplevel]
"Exit with error code 2 if Infer found something to report"
and failures_allowed =
CLOpt.mk_bool ~deprecated_no:["-no_failures_allowed"] ~long:"failures-allowed" ~default:true
"Fail if at least one of the translations fails"
"Fail if at least one of the translations fails (clang only)"
and filtering =
CLOpt.mk_bool ~long:"filtering" ~short:"f" ~default:true
"Also show the results from the experimental checks. Warning: some checks may contain many \
false alarms."
~exes:CLOpt.[Toplevel]
"Do not show the results from experimental checks (note: some of them may contain many false \
alarms)"
and flavors =
CLOpt.mk_bool ~deprecated:["-use-flavors"] ~long:"flavors"
"Buck integration using flavors."
~exes:CLOpt.[Toplevel]
"Buck integration using Buck flavors (clang only), eg `infer --flavors -- buck build \
//foo:bar#infer`"
and frontend_debug =
CLOpt.mk_bool ~long:"frontend-debug" ~short:"fd"
"Emit debug info to *.o.astlog and a script *.o.sh that replays the command used to run clang \
with the plugin attached, piped to the InferClang frontend command (clang only)"
and frontend_stats =
CLOpt.mk_bool ~long:"frontend-stats" ~short:"fs"
"Output statistics about the capture phase to *.o.astlog"
"Output statistics about the capture phase to *.o.astlog (clang only)"
and headers =
CLOpt.mk_bool ~deprecated:["headers"] ~deprecated_no:["no_headers"] ~long:"headers" ~short:"hd"
~exes:CLOpt.[Clang]
"Analyze code in header files"
and infer_cache =
CLOpt.mk_string_opt ~deprecated:["infer_cache"; "-infer_cache"] ~long:"infer-cache" ~f:resolve
~meta:"dir" "Select a directory to contain the infer cache"
~meta:"dir" "Select a directory to contain the infer cache (Buck and Java only)"
(** Set the timeout values in seconds and symops, computed as a multiple of the integer
parameter *)
and iterations =
CLOpt.mk_int ~deprecated:["iterations"] ~long:"iterations" ~default:1
~meta:"int"
"Specify the maximum number of operations for each function, expressed as a multiple \
of symbolic operations"
"Specify the maximum number of operations for each function, expressed as a multiple of \
symbolic operations and a multiple of seconds of elapsed time"
and jobs =
CLOpt.mk_int ~deprecated:["-multicore"] ~long:"jobs" ~short:"j" ~default:ncpu
~exes:CLOpt.[Toplevel] ~meta:"int" "Run the specified number of analysis jobs simultaneously"
(** Flag to tune the final information-loss check used by the join
0 = use the most aggressive join for preconditions
1 = use the least aggressive join for preconditions
*)
and join_cond =
CLOpt.mk_int ~deprecated:["join_cond"] ~long:"join-cond" ~default:1
~meta:"int" "Set the strength of the final information-loss check used by the join"
~meta:"int" "Set the strength of the final information-loss check used by the join:\n\
- 0 = use the most aggressive join for preconditions\n\
- 1 = use the least aggressive join for preconditions"
(** Outfile to save the latex report *)
and latex =
CLOpt.mk_option ~deprecated:["latex"] ~long:"latex" ~f:create_outfile
~meta:"file.tex" "Print latex report to file.tex"
~meta:"file" "Print latex report to a file"
and load_average =
CLOpt.mk_option ~long:"load-average" ~short:"l" ~f:(fun s -> Some (float_of_string s))
~meta:"float"
"Do not start new parallel jobs if the load average is greater than that specified"
~exes:CLOpt.[Toplevel]
"Do not start new parallel jobs if the load average is greater than that specified (Buck and \
make only)"
(** name of the file to load analysis results from *)
and load_results =
CLOpt.mk_string_opt ~deprecated:["load_results"] ~long:"load-results"
~exes:CLOpt.[Print]
~meta:"file.iar" "Load analysis results from Infer Analysis Results file file.iar"
and llvm =
@ -765,58 +789,55 @@ and llvm =
(** name of the makefile to create with clusters and dependencies *)
and makefile =
CLOpt.mk_string ~deprecated:["makefile"] ~long:"makefile" ~default:""
~exes:CLOpt.[Analyze] ~meta:"file" "create a makefile to perform the analysis"
~meta:"file" ""
(** Merge the captured results directories specified in the dependency file *)
and merge =
CLOpt.mk_bool ~deprecated:["merge"] ~long:"merge"
"Merge the captured results directories specified in the dependency file"
~exes:CLOpt.[Toplevel]
"Merge the captured results directories specified in the dependency file (Buck flavors only)"
(** List of obj memory leak buckets to be checked in Objective-C/C++ *)
and ml_buckets =
CLOpt.mk_symbol_seq ~deprecated:["ml_buckets"; "-ml_buckets"] ~long:"ml-buckets"
~default:[`MLeak_cf]
~exes:CLOpt.[Toplevel]
"Specify the memory leak buckets to be checked: \
'cf' checks leaks from Core Foundation, \
'arc' from code compiled in ARC mode, \
'narc' from code not compiled in ARC mode, \
'cpp' from C++ code"
~exes:CLOpt.[Clang]
"Specify the memory leak buckets to be checked in Objective-C/C++:\n\
- 'cf' checks leaks from Core Foundation,\n\
- 'arc' from code compiled in ARC mode,\n\
- 'narc' from code not compiled in ARC mode,\n\
- 'cpp' from C++ code"
~symbols:ml_bucket_symbols
(* Add a zip file containing the Java models *)
and models_file =
CLOpt.mk_string_opt ~deprecated:["models"] ~long:"models"
~exes:CLOpt.[Analyze;Java] ~meta:"zip file" "add a zip file containing the models"
~meta:"zip file" ""
and models_mode =
CLOpt.mk_bool ~deprecated:["models_mode"; "-models_mode"] ~long:"models-mode"
"Mode for computing the models"
"Mode for analyzing the models"
and modified_targets =
CLOpt.mk_string_opt ~deprecated:["modified_targets"] ~long:"modified-targets"
~meta:"file" "Read the file of buck targets modified since the last analysis"
~meta:"file" "Read the file of Buck targets modified since the last analysis"
(** Monitor the size of the props, and print every time the current max is exceeded *)
and monitor_prop_size =
CLOpt.mk_bool ~deprecated:["monitor_prop_size"] ~long:"monitor-prop-size"
"Monitor size of props"
"Monitor size of props, and print every time the current max is exceeded"
(** Flag for using the nonempty lseg only **)
and nelseg =
CLOpt.mk_bool ~deprecated:["nelseg"] ~long:"nelseg"
"Use only nonempty lsegs"
(** true if the current objective-c source file is compiled with automatic reference counting
(ARC) *)
(* Translate with Objective-C Automatic Reference Counting (ARC) *)
and objc_arc =
CLOpt.mk_bool ~deprecated:["fobjc-arc"] ~long:"objc-arc"
"Translate with Objective-C Automatic Reference Counting (ARC)"
""
(* TODO: document *)
and objc_memory_model =
CLOpt.mk_bool ~deprecated:["objcm"] ~long:"objc-memory-model"
"Use ObjC memory model"
(** if true, skip the re-execution phase *)
and only_footprint =
CLOpt.mk_bool ~deprecated:["only_footprint"] ~long:"only-footprint"
"Skip the re-execution phase"
@ -827,7 +848,7 @@ and optimistic_cast =
and out_file =
CLOpt.mk_string ~deprecated:["out_file"] ~long:"out-file" ~default:""
~exes:CLOpt.[Analyze] ~meta:"file" "use file for the out channel"
~meta:"file" "Specify the file for the non-error logs of the analyzer"
and margin =
CLOpt.mk_int ~deprecated:["set_pp_margin"] ~long:"margin" ~default:100
@ -842,120 +863,110 @@ and (
~exes:CLOpt.[Java]
~f:(patterns_of_json_with_key long) doc in
( mk_option ~deprecated:["modeled_expensive"] ~long:"modeled-expensive"
("Matcher or list of matchers for methods that should be considered expensive " ^
"by the performance critical checker."),
"Matcher or list of matchers for methods that should be considered expensive by the \
performance critical checker.",
mk_option ~deprecated:["never_returning_null"] ~long:"never-returning-null"
"Matcher or list of matchers for functions that never return `null`.",
mk_option ~deprecated:["skip_translation"] ~long:"skip-translation"
"Matcher or list of matchers for names of files that should be analyzed at all.")
and pmd_xml =
CLOpt.mk_bool ~long:"pmd-xml"
CLOpt.mk_bool ~long:"pmd-xml"
~exes:CLOpt.[Toplevel]
"Output issues in (PMD) XML format"
(** command line flag: if true, print stats about preconditions to standard output *)
and precondition_stats =
CLOpt.mk_bool ~deprecated:["precondition_stats"] ~long:"precondition-stats"
"Print stats about preconditions to standard output"
(** if true, show buckets in textual description of errors *)
and print_buckets =
CLOpt.mk_bool ~deprecated:["print_buckets"] ~long:"print-buckets"
"Add buckets to issue descriptions, useful when developing infer"
"Show the internal bucket of Infer reports in their textual description"
and print_builtins =
CLOpt.mk_bool ~deprecated:["print_builtins"] ~long:"print-builtins"
"Print the builtin functions and exit"
(** if true, acrtivate color printing by diff'ing w.r.t. previous prop *)
and print_using_diff =
CLOpt.mk_bool ~deprecated_no:["noprintdiff"] ~long:"print-using-diff" ~default:true
"Highlighting diff w.r.t. previous prop in printing"
"Highlight the difference w.r.t. the previous prop when printing symbolic execution debug info"
(** Outfile to save procedures stats in csv format *)
and procs_csv =
CLOpt.mk_option ~deprecated:["procs"] ~long:"procs-csv" ~f:create_outfile
~meta:"procs.csv" "Create file procs.csv containing statistics for each procedure in CSV format"
~meta:"file" "Create a file containing statistics for each procedure in CSV format"
(** Outfile to save procedures stats in xml format *)
and procs_xml =
CLOpt.mk_option ~deprecated:["procs_xml"] ~long:"procs-xml" ~f:create_outfile
~meta:"procs.xml" "Create file procs.xml containing statistics for each procedure in XML format"
~meta:"file" "Create a file containing statistics for each procedure in XML format"
and progress_bar =
CLOpt.mk_bool ~deprecated_no:["no_progress_bar"] ~long:"progress-bar" ~short:"pb" ~default:true
~exes:CLOpt.[Toplevel]
"Show a progress bar"
(** command line flag: if true, do not print the spec to standard output *)
and quiet =
CLOpt.mk_bool ~long:"quiet" ~short:"q"
~exes:CLOpt.[Print]
"Do not print specs on standard output"
(** flag for reactive mode:
the analysis starts from the files captured since the "infer" command started *)
and reactive =
CLOpt.mk_bool ~deprecated:["reactive"] ~long:"reactive"
"Reactive propagation mode starting analysis from changed files"
"Reactive mode: the analysis starts from the files captured since the `infer` command started"
(** Outfile to save the analysis report *)
and report =
CLOpt.mk_option ~deprecated:["report"] ~long:"report" ~f:create_outfile
~meta:"report_file" "Create file report_file containing a report of the analysis results"
~meta:"file" "Create a file containing a report of the analysis results"
(** If true then include Infer source code locations in json reports *)
and reports_include_ml_loc =
CLOpt.mk_bool ~deprecated:["with_infer_src_loc"] ~long:"reports-include-ml-loc"
"Include the location (in the Infer source code) from where reports are generated"
"Include the location in the Infer source code from where reports are generated"
and results_dir =
CLOpt.mk_string ~deprecated:["results_dir"; "-out"] ~long:"results-dir" ~short:"o"
~default:(init_work_dir // "infer-out")
~exes:CLOpt.[Analyze;Clang;Java;Llvm;Print;StatsAggregator]
~meta:"dir" "Write results in the specified directory"
~meta:"dir" "Write results and internal files in the specified directory"
(** name of the file to load save results to *)
and save_results =
CLOpt.mk_string_opt ~deprecated:["save_results"] ~long:"save-results"
~meta:"file.iar" "Save analysis results to Infer Analysis Results file file.iar"
(** number of seconds to multiply by the number of iterations, after which there is a timeout *)
and seconds_per_iteration =
CLOpt.mk_float ~deprecated:["seconds_per_iteration"] ~long:"seconds-per-iteration" ~default:0.
~meta:"float" "Set the number of seconds per iteration"
~meta:"float" "Set the number of seconds per iteration (see --iterations)"
and skip_clang_analysis_in_path =
CLOpt.mk_string_list ~long:"skip-clang-analysis-in-path"
~exes:CLOpt.[Clang] ~meta:"path prefix" "Ignore files whose path matches the given prefix"
~exes:CLOpt.[Clang]
~meta:"path prefix" "Ignore files whose path matches the given prefix"
and skip_translation_headers =
CLOpt.mk_string_list ~deprecated:["skip_translation_headers"] ~long:"skip-translation-headers"
~exes:CLOpt.[Clang]
~meta:"path prefix" "Ignore headers whose path matches the given prefix"
(* clang-plugin normalizes filenames *)
(** File to translate *)
and source_file =
(* clang-plugin normalizes filenames *)
CLOpt.mk_string_opt ~long:"source-file" ~short:"c" ~f:filename_to_absolute
~meta:"file" "File to translate"
~meta:"file" ""
(** command-line option to print the location of the copy of a source file *)
and source_file_copy =
CLOpt.mk_string_opt ~deprecated:["source_file_copy"] ~long:"source-file-copy"
~meta:"source_file" "Print the path of the copy of source_file in the results directory"
(** Flag to tune the level of abstracting the postconditions of specs discovered
by the footprint analysis.
0 = nothing special.
1 = filter out redundant posts implied by other posts. *)
and spec_abs_level =
CLOpt.mk_int ~deprecated:["spec_abs_level"] ~long:"spec-abs-level" ~default:1
~meta:"int" "Set the level of abstracting the postconditions of discovered specs"
~meta:"int" "Set the level of abstracting the postconditions of discovered specs:\n\
- 0 = nothing special\n\
- 1 = filter out redundant posts implied by other posts"
(** List of paths to the directories containing specs for library functions. *)
and specs_library =
(* Add dir to the list of directories to be searched for .spec files *)
let specs_library =
CLOpt.mk_string_list ~long:"specs-library" ~short:"lib" ~f:resolve
~exes:CLOpt.[Analyze] ~meta:"dir"
"add dir to the list of directories to be searched for spec files" in
~meta:"dir"
"" in
let _ =
(* Given a filename with a list of paths, convert it into a list of string iff they are
absolute *)
@ -969,101 +980,95 @@ and specs_library =
pathlist
| None -> failwith ("cannot read file " ^ fname ^ " from cwd " ^ (Sys.getcwd ()))
in
(* Add the newline-separated directories listed in <file> to the list of directories to be
searched for .spec files *)
CLOpt.mk_string ~deprecated:["specs-dir-list-file"; "-specs-dir-list-file"]
~long:"specs-library-index"
~default:""
~f:(fun file -> specs_library := (read_specs_dir_list_file file) @ !specs_library; "")
~exes:CLOpt.[Analyze] ~meta:"file"
"add the newline-separated directories listed in <file> to the list of directories to be \
searched for spec files" in
"" in
specs_library
(** JSON encoded Java stacktrace file, currently used only for -a crashcontext *)
and stacktrace =
CLOpt.mk_string_opt ~long:"stacktrace" ~short:"st" ~f:resolve ~exes:CLOpt.[Analyze]
~meta:"file" "File path containing a json encoded crash stacktrace. \
Used to guide the analysis (currently acknowledged by -a crashcontext)"
CLOpt.mk_string_opt ~long:"stacktrace" ~short:"st" ~f:resolve
~meta:"file" "File path containing a json-encoded Java crash stacktrace. Used to guide the \
analysis (only with '-a crashcontext'). See \
tests/codetoanalyze/java/crashcontext/*.json for examples of the expected format"
(** If active, enable special treatment of static final fields. *)
and static_final =
CLOpt.mk_bool ~deprecated_no:["no-static_final"] ~long:"static-final" ~default:true
"Special treatment for static final fields"
and stats =
CLOpt.mk_bool ~deprecated:["stats"] ~long:"stats" "Enables stats mode"
CLOpt.mk_bool ~deprecated:["stats"] ~long:"stats" "Stats mode (debugging)"
(** Flag to activate nonstop mode: the analysis continues after in encounters errors *)
and no_stop =
CLOpt.mk_bool ~deprecated:["nonstop"] ~long:"no-stop"
"Nonstop mode: the analysis continues after finding errors. \
With this option the analysis can become less precise."
"Nonstop mode: the analysis continues after finding errors. With this option the analysis can \
become less precise."
and subtype_multirange =
CLOpt.mk_bool ~deprecated:["subtype_multirange"] ~long:"subtype-multirange" ~default:true
"Use the multirange subtyping domain"
(* Path to list of collected @SuppressWarnings annotations *)
and suppress_warnings_out =
CLOpt.mk_string_opt ~deprecated:["suppress_warnings_out"] ~long:suppress_warnings_annotations_long
~exes:CLOpt.[Java] ~meta:"path" "Path to list of collected @SuppressWarnings annotations"
~meta:"path" ""
(** command line flag: if true, produce a svg file *)
and svg =
CLOpt.mk_bool ~deprecated:["svg"] ~long:"svg"
"Generate .dot and .svg"
"Generate .dot and .svg files from specs"
(** number of symops to multiply by the number of iterations, after which there is a timeout *)
and symops_per_iteration =
CLOpt.mk_int ~deprecated:["symops_per_iteration"] ~long:"symops-per-iteration" ~default:0
~meta:"int" "Set the number of symbolic operations per iteration"
~meta:"int" "Set the number of symbolic operations per iteration (see --iterations)"
(** Flag for test mode *)
and test =
CLOpt.mk_bool ~deprecated_no:["notest"] ~long:"test" ~default:true
"Test mode"
CLOpt.mk_bool ~deprecated_no:["notest"] ~deprecated:["-test"] ~long:"only-cheap-debug"
~default:true
"Disable expensive debugging output"
(** command line option to test the filtering based on .inferconfig *)
and test_filtering =
CLOpt.mk_bool ~deprecated:["test_filtering"] ~long:"test-filtering"
"List all the files Infer can report on (should be call at the root of the project)"
"List all the files Infer can report on (should be called from the root of the project)"
and testing_mode =
CLOpt.mk_bool ~deprecated:["testing_mode"; "-testing_mode"] ~long:"testing-mode" ~short:"tm"
"Mode for testing, where no headers are translated, and dot files are created"
"Mode for testing, where no headers are translated, and dot files are created (clang only)"
(** Flag set to enable detailed tracing informatin during error explanation *)
and trace_error =
CLOpt.mk_bool ~deprecated:["trace_error"] ~long:"trace-error"
"Turn on tracing of error explanation"
"Detailed tracing information during error explanation"
(** Flag set to enable detailed tracing information during join *)
and trace_join =
CLOpt.mk_bool ~deprecated:["trace_join"] ~long:"trace-join"
"Turn on tracing of join"
"Detailed tracing information during prop join operations"
(** Flag set to enable detailed tracing information during re-arrangement *)
and trace_rearrange =
CLOpt.mk_bool ~deprecated:["trace_rearrange"] ~long:"trace-rearrange"
"Turn on tracing of rearrangement"
"Detailed tracing information during prop re-arrangement operations"
(** if true, generate preconditions for runtime exceptions in Java and report errors for the public
methods having preconditions to throw runtime exceptions *)
(** Report error traces for runtime exceptions (Java only): generate preconditions for runtime
exceptions in Java and report errors for public methods which throw runtime exceptions *)
and tracing =
CLOpt.mk_bool ~deprecated:["tracing"] ~long:"tracing"
"Report error traces for runtime exceptions (Only for Java)"
""
(** Consider the size of types during analysis, e.g. cannot use an int pointer to write to a char *)
and type_size =
CLOpt.mk_bool ~deprecated:["type_size"] ~long:"type-size"
"Consider the size of types during analysis"
"Consider the size of types during analysis, e.g. cannot use an int pointer to write to a char"
and unsafe_malloc =
CLOpt.mk_bool ~long:"unsafe-malloc"
~exes:CLOpt.[Analyze;Toplevel]
~exes:CLOpt.[Analyze]
"Assume that malloc(3) never returns null."
(** Set the path to the javac verbose output *)
and verbose_out =
CLOpt.mk_string ~deprecated:["verbose_out"] ~long:"verbose-out" ~default:""
~exes:CLOpt.[Java] ~meta:"file" "Set the path to the javac verbose output"
~meta:"file" ""
and version =
CLOpt.mk_bool ~deprecated:["version"] ~long:"version"
@ -1071,9 +1076,9 @@ and version =
and version_json =
CLOpt.mk_bool ~deprecated:["version_json"] ~long:"version-json"
~exes:CLOpt.[Analyze;Clang;Java;Llvm;Print]
"Print version json formatted"
(** command line flag: if true, print whole seconds only *)
and whole_seconds =
CLOpt.mk_bool ~deprecated:["whole_seconds"] ~long:"whole-seconds"
"Print whole seconds only"
@ -1084,7 +1089,7 @@ and whole_seconds =
2 least visited first *)
and worklist_mode =
let var = ref 0 in
CLOpt.mk_set var 2 ~long:"coverage" ~exes:CLOpt.[Analyze]
CLOpt.mk_set var 2 ~long:"coverage"
"analysis mode to maximize coverage (can take longer)" ;
CLOpt.mk_set var 1 ~long:"exit-node-bias" ~deprecated:["exit_node_bias"]
"nodes nearest the exit node are analyzed first" ;
@ -1092,12 +1097,15 @@ and worklist_mode =
"nodes visited fewer times are analyzed first" ;
var
(** flag: if true write html files in db dir *)
and write_html =
CLOpt.mk_bool ~deprecated:["html"] ~long:"write-html"
"Produce hmtl output in the results directory"
"Produce hmtl debug output in the results directory"
and xcode_developer_dir =
CLOpt.mk_string_opt ~long:"xcode-developer-dir"
~exes:CLOpt.[Toplevel]
~meta:"XCODE_DEVELOPER_DIR" "Specify the path to Xcode developer directory (Buck flavors only)"
(** command line flag: if true, export specs to xml files *)
and xml_specs =
CLOpt.mk_bool ~deprecated:["xml"] ~long:"xml-specs"
"Export specs into XML files file1.xml ... filen.xml"
@ -1107,7 +1115,7 @@ and zip_libraries : zip_library list ref = ref []
and zip_specs_library =
CLOpt.mk_string_list ~long:"zip-specs-library" ~short:"ziplib" ~f:resolve
~exes:CLOpt.[Analyze] ~meta:"zip file" "add a zip file containing library spec files"
~meta:"zip file" "Search for .spec files in a zip file"
(** Configuration values specified by environment variables *)
@ -1324,9 +1332,11 @@ and dotty_cfg_libs = !dotty_cfg_libs
and enable_checks = !enable_checks
and eradicate = !eradicate
and err_file_cmdline = !err_file
and fail_on_bug = !fail_on_bug
and failures_allowed = !failures_allowed
and filtering = !filtering
and flavors = !flavors
and frontend_debug = !frontend_debug
and frontend_stats = !frontend_stats
and headers = !headers
and infer_cache = !infer_cache
@ -1396,6 +1406,7 @@ and whole_seconds = !whole_seconds
and worklist_mode = !worklist_mode
and write_dotty = !write_dotty
and write_html = !write_html
and xcode_developer_dir = !xcode_developer_dir
and xml_specs = !xml_specs
and zip_libraries = !zip_libraries

@ -176,9 +176,11 @@ val dotty_cfg_libs : bool
val enable_checks : string list
val eradicate : bool
val err_file_cmdline : string
val fail_on_bug : bool
val failures_allowed : bool
val filtering : bool
val flavors : bool
val frontend_debug : bool
val frontend_stats : bool
val headers : bool
val infer_cache : string option
@ -246,6 +248,7 @@ val whole_seconds : bool
val worklist_mode : int
val write_dotty : bool
val write_html : bool
val xcode_developer_dir : string option
val xml_specs : bool
val zip_libraries : zip_library list

@ -53,6 +53,8 @@ let () =
Array.of_list (
infer_py ::
Config.anon_args @
(if not Config.absolute_paths then [] else
["--absolute-paths"]) @
(match Config.analyzer with None -> [] | Some a ->
["--analyzer";
IList.assoc (=) a (IList.map (fun (n,a) -> (a,n)) Config.string_to_analyzer)]) @
@ -73,8 +75,14 @@ let () =
["--debug"]) @
(if not Config.debug_exceptions then [] else
["--debug-exceptions"]) @
(if not Config.fail_on_bug then [] else
["--fail-on-bug"]) @
(if Config.filtering then [] else
["--no-filtering"]) @
(if not Config.frontend_debug then [] else
["--frontend-debug"]) @
(if not Config.frontend_stats then [] else
["--frontend-stats"]) @
(if not Config.flavors || not buck then [] else
["--use-flavors"]) @
(match Config.infer_cache with None -> [] | Some s ->
@ -88,7 +96,9 @@ let () =
["--reactive"]) @
"--out" :: Config.results_dir ::
(match Config.project_root with None -> [] | Some pr ->
["--project_root"; pr]) @
["--project_root"; pr]) @
(match Config.xcode_developer_dir with None -> [] | Some d ->
["--xcode-developer-dir"; d]) @
(if Config.rest = [] then [] else
("--" :: build_cmd))
) in

Loading…
Cancel
Save