diff --git a/infer/src/base/CommandDoc.ml b/infer/src/base/CommandDoc.ml index 431faecb4..cc2a75481 100644 --- a/infer/src/base/CommandDoc.ml +++ b/infer/src/base/CommandDoc.ml @@ -161,12 +161,12 @@ $(b,infer) $(i,[options])|} "Infer is a static analyzer. Given a collection of source files written in Java or in languages of the C family, and a command to build them, infer produces a list of potential issues." ; `P "Infer consists of a collection of tools referenced in the $(i,SEE ALSO) section of this manual. See their respective manuals for more information about each." + ; `P + "If a compilation command is specified via the $(b,--) option or one of the $(b,--clang-compilation-database[-escaped]) options, $(b,infer) behaves as $(b,infer-run)(1). Otherwise, $(b,infer) behaves as $(b,infer-analyze)(1)." ] ~options: (`Prepend [ `P - "If a compilation command is specified via the $(b,--) option or one of the $(b,--clang-compilation-database[-escaped]) options, $(b,infer) behaves as $(b,infer-run)(1). Otherwise, $(b,infer) behaves as $(b,infer-analyze)(1)." - ; `P "Every infer command accepts the arguments from all the other infer commands. The same option may affect and thus be list in the manual of several commands." ; `P (Printf.sprintf @@ -175,6 +175,8 @@ $(b,infer) $(i,[options])|} CLOpt.args_env_var Cmdliner.Manpage.s_environment Cmdliner.Manpage.s_files) ; `P "Options can be specified inside an argument file $(i,file) by passing $(b,@)$(i,file) as argument. The format is one option per line, and enclosing single ' and double \" quotes are ignored." + ; `P + "Options without a default value (e.g., $(b,--linter)) and options with list-like values (e.g., $(b,--Xbuck)) all have a corresponding $(b,--option-reset) flag that resets their values to nothing or the empty list, respectively. For instance, $(b,--Xbuck-reset) will cancel any previous $(b,--Xbuck) option passed to infer." ; `P "See the manuals of individual infer commands for details about their supported options. The following is a list of all the supported options (see also $(b,--help-full) for options reserved for internal use)." ]) diff --git a/infer/src/base/CommandLineOption.ml b/infer/src/base/CommandLineOption.ml index bec4e2a4f..736f24257 100644 --- a/infer/src/base/CommandLineOption.ml +++ b/infer/src/base/CommandLineOption.ml @@ -316,11 +316,27 @@ let mk_set var value ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= ~default_to_string:(fun () -> "") ~decode_json:(string_json_decoder ~long) ~mk_setter:(fun _ _ -> setter ()) ~mk_spec:(fun _ -> Unit setter )) +let mk_with_reset value ~reset_doc ?deprecated ~long ?parse_mode mk = + let var = mk () in + if not (String.equal "" long) then + (* Do not pass any ~in_help value so that the reset options only show up in --help-full and do + not clutter --help. *) + mk_set var value ?deprecated ~long:(long ^ "-reset") ?parse_mode reset_doc ; + var + +let reset_doc_opt ~long = Printf.sprintf "Cancel the effect of $(b,%s)." (dashdash long) + +let reset_doc_list ~long = Printf.sprintf "Set $(b,%s) to the empty list." (dashdash long) + let mk_option ?(default= None) ?(default_to_string= fun _ -> "") ~f ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= "string") doc = - mk ~deprecated ~long ?short ~default ?parse_mode ?in_help ~meta doc ~default_to_string - ~decode_json:(string_json_decoder ~long) ~mk_setter:(fun var str -> var := f str) ~mk_spec: - (fun set -> String set ) + let mk () = + mk ~deprecated ~long ?short ~default ?parse_mode ?in_help ~meta doc ~default_to_string + ~decode_json:(string_json_decoder ~long) ~mk_setter:(fun var str -> var := f str) ~mk_spec: + (fun set -> String set ) + in + let reset_doc = reset_doc_opt ~long in + mk_with_reset None ~reset_doc ~long ?parse_mode mk let mk_bool ?(deprecated_no= []) ?(default= false) ?(f= fun b -> b) ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= "") doc = @@ -407,10 +423,15 @@ let mk_string_opt ?default ?(f= fun s -> s) ?(deprecated= []) ~long ?short ?pars mk_option ~deprecated ~long ?short ~default ~default_to_string ~f ?parse_mode ?in_help ~meta doc let mk_string_list ?(default= []) ?(f= fun s -> s) ?(deprecated= []) ~long ?short ?parse_mode - ?in_help ?(meta= "+string") doc = - mk ~deprecated ~long ?short ~default ?parse_mode ?in_help ~meta doc - ~default_to_string:(String.concat ~sep:", ") ~mk_setter:(fun var str -> var := f str :: !var) - ~decode_json:(list_json_decoder (string_json_decoder ~long)) ~mk_spec:(fun set -> String set ) + ?in_help ?(meta= "string") doc = + let mk () = + mk ~deprecated ~long ?short ~default ?parse_mode ?in_help ~meta:("+" ^ meta) doc + ~default_to_string:(String.concat ~sep:", ") ~mk_setter:(fun var str -> var := f str :: !var) + ~decode_json:(list_json_decoder (string_json_decoder ~long)) ~mk_spec:(fun set -> String set + ) + in + let reset_doc = reset_doc_list ~long in + mk_with_reset [] ~reset_doc ~long ?parse_mode mk let normalize_path_in_args_being_parsed ?(f= Fn.id) ~is_anon_arg str = if Filename.is_relative str then @@ -439,20 +460,28 @@ let mk_path ~default ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= ~default_to_string:(fun s -> s) ~default ~deprecated ~long ~short ~parse_mode ~in_help ~meta -let mk_path_opt ?default ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= "path") = - mk_path_helper - ~setter:(fun var x -> var := Some x) - ~decode_json:(path_json_decoder ~long) - ~default_to_string:(function Some s -> s | None -> "") - ~default ~deprecated ~long ~short ~parse_mode ~in_help ~meta +let mk_path_opt ?default ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= "path") doc = + let mk () = + mk_path_helper + ~setter:(fun var x -> var := Some x) + ~decode_json:(path_json_decoder ~long) + ~default_to_string:(function Some s -> s | None -> "") + ~default ~deprecated ~long ~short ~parse_mode ~in_help ~meta doc + in + let reset_doc = reset_doc_opt ~long in + mk_with_reset None ~reset_doc ~long ?parse_mode mk -let mk_path_list ?(default= []) ?(deprecated= []) ~long ?short ?parse_mode ?in_help - ?(meta= "+path") = - mk_path_helper - ~setter:(fun var x -> var := x :: !var) - ~decode_json:(list_json_decoder (path_json_decoder ~long)) - ~default_to_string:(String.concat ~sep:", ") ~default ~deprecated ~long ~short ~parse_mode - ~in_help ~meta +let mk_path_list ?(default= []) ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?(meta= "path") + doc = + let mk () = + mk_path_helper + ~setter:(fun var x -> var := x :: !var) + ~decode_json:(list_json_decoder (path_json_decoder ~long)) + ~default_to_string:(String.concat ~sep:", ") ~default ~deprecated ~long ~short ~parse_mode + ~in_help ~meta:("+" ^ meta) doc + in + let reset_doc = reset_doc_list ~long in + mk_with_reset [] ~reset_doc ~long ?parse_mode mk let mk_symbols_meta symbols = let strings = List.map ~f:fst symbols in @@ -473,9 +502,13 @@ let mk_symbol_opt ~symbols ?(f= Fn.id) ?(deprecated= []) ~long ?short ?parse_mod let strings = List.map ~f:fst symbols in let of_string str = List.Assoc.find_exn ~equal:String.equal symbols str in let meta = Option.value meta ~default:(mk_symbols_meta symbols) in - mk ~deprecated ~long ?short ~default:None ?parse_mode ?in_help ~meta doc - ~default_to_string:(fun _ -> "") ~mk_setter:(fun var str -> var := Some (f (of_string str))) - ~decode_json:(string_json_decoder ~long) ~mk_spec:(fun set -> Symbol (strings, set) ) + let mk () = + mk ~deprecated ~long ?short ~default:None ?parse_mode ?in_help ~meta doc + ~default_to_string:(fun _ -> "") ~mk_setter:(fun var str -> var := Some (f (of_string str))) + ~decode_json:(string_json_decoder ~long) ~mk_spec:(fun set -> Symbol (strings, set) ) + in + let reset_doc = reset_doc_opt ~long in + mk_with_reset None ~reset_doc ~long ?parse_mode mk let mk_symbol_seq ?(default= []) ~symbols ~eq ?(deprecated= []) ~long ?short ?parse_mode ?in_help ?meta doc = diff --git a/infer/src/base/CommandLineOption.mli b/infer/src/base/CommandLineOption.mli index e502f1d0c..b4cdb287b 100644 --- a/infer/src/base/CommandLineOption.mli +++ b/infer/src/base/CommandLineOption.mli @@ -106,7 +106,10 @@ val mk_string_opt : ?default:string -> ?f:(string -> string) -> string option re val mk_string_list : ?default:string list -> ?f:(string -> string) -> string list ref t (** [mk_string_list] defines a [string list ref], initialized to [[]] unless overridden by [~default]. Each argument of an occurrence of the option will be prepended to the list, so the - final value will be in the reverse order they appeared on the command line. *) + final value will be in the reverse order they appeared on the command line. + + An option "--[long]-reset" is automatically created that resets the list to [] when found on the + command line. *) val mk_path : default:string -> string ref t (** like [mk_string] but will resolve the string into an absolute path so that children processes diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 8c31fd776..acfb5500f 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -538,11 +538,11 @@ and ( analysis_blacklist_files_containing_options , 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 (to whitelist: $(b,---whitelist-path-regex))" - ~meta:"path regex" + ~meta:"path_regex" , mk_filtering_options ~suffix:"whitelist-path-regex" ~deprecated_suffix:["whitelist"] ~help:"" - ~meta:"path regex" + ~meta:"path_regex" , mk_filtering_options ~suffix:"suppress-errors" ~deprecated_suffix:["suppress_errors"] - ~help:"do not report a type of errors" ~meta:"error name" ) + ~help:"do not report a type of errors" ~meta:"error_name" ) and analysis_stops = CLOpt.mk_bool ~deprecated:["analysis_stops"] ~long:"analysis-stops" @@ -792,11 +792,11 @@ and clang_frontend_action = and clang_include_to_override_regex = CLOpt.mk_string_opt ~long:"clang-include-to-override-regex" - ~deprecated:["-clang-include-to-override"] ~meta:"dir OCaml regex" + ~deprecated:["-clang-include-to-override"] ~meta:"dir_OCaml_regex" "Use this option in the uncommon case where the normal compilation process overrides the location of internal compiler headers. This option should specify regular expression with the path to those headers so that infer can use its own clang internal headers instead." and clang_ignore_regex = - CLOpt.mk_string_opt ~long:"clang-ignore-regex" ~meta:"dir OCaml regex" + CLOpt.mk_string_opt ~long:"clang-ignore-regex" ~meta:"dir_OCaml_regex" "The files in this regex will be ignored in the compilation process and an empty file will be passed to clang instead. This is to be used with the buck flavour infer-capture-all to work around missing generated files." and classpath = CLOpt.mk_string_opt ~long:"classpath" "Specify the Java classpath" @@ -1026,7 +1026,7 @@ and differential_filter_set = ~default:[`Introduced; `Fixed; `Preexisting] and disable_checks = - CLOpt.mk_string_list ~deprecated:["disable_checks"] ~long:"disable-checks" ~meta:"error name" + CLOpt.mk_string_list ~deprecated:["disable_checks"] ~long:"disable-checks" ~meta:"error_name" ~in_help:CLOpt.([(Report, manual_generic)]) ~default: [ "ANALYSIS_STOPS" @@ -1061,7 +1061,7 @@ and dynamic_dispatch = ~symbols:[("none", `None); ("interface", `Interface); ("sound", `Sound); ("lazy", `Lazy)] and enable_checks = - CLOpt.mk_string_list ~deprecated:["enable_checks"] ~long:"enable-checks" ~meta:"error name" + CLOpt.mk_string_list ~deprecated:["enable_checks"] ~long:"enable-checks" ~meta:"error_name" "Show reports coming from this type of errors. This option has higher precedence than $(b,--disable-checks)" and eradicate_condition_redundant = @@ -1184,7 +1184,7 @@ and iphoneos_target_sdk_version = and iphoneos_target_sdk_version_skip_path = CLOpt.mk_string_list ~long:"iphoneos-target-sdk-version-skip-path" ~in_help:CLOpt.([(Capture, manual_clang_linters)]) - ~meta:"path prefix OCaml regex" + ~meta:"path_prefix_OCaml_regex" "To be used together with iphoneos-target-sdk-version, to disable that flag in a particular path (can be specified multiple times)" and issues_fields = @@ -1508,7 +1508,7 @@ and siof_safe_methods = and skip_analysis_in_path = CLOpt.mk_string_list ~deprecated:["-skip-clang-analysis-in-path"] ~long:"skip-analysis-in-path" ~in_help:CLOpt.([(Capture, manual_generic); (Run, manual_generic)]) - ~meta:"path prefix OCaml regex" + ~meta:"path_prefix_OCaml_regex" "Ignore files whose path matches the given prefix (can be specified multiple times)" and skip_analysis_in_path_skips_compilation = @@ -1524,7 +1524,7 @@ and skip_duplicated_types = and skip_translation_headers = CLOpt.mk_string_list ~deprecated:["skip_translation_headers"] ~long:"skip-translation-headers" ~in_help:CLOpt.([(Capture, manual_clang)]) - ~meta:"path prefix" "Ignore headers whose path matches the given prefix" + ~meta:"path_prefix" "Ignore headers whose path matches the given prefix" and source_preview = CLOpt.mk_bool ~long:"source-preview" ~default:true