From 4e249b8cc3e84321b2e7c87be22546c3ea474f02 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Wed, 24 Apr 2019 01:37:36 -0700 Subject: [PATCH] Improve man page for infer explore Summary: - `--source-files` was missing. - The three modes are actually independent, make it clearer and group options by mode. - Fail if `--procedures` and `--source-files` are used together. Reviewed By: jeremydubreil Differential Revision: D15049822 fbshipit-source-id: cc515cb56 --- infer/man/man1/infer-explore.txt | 36 ++++++------ infer/src/base/CommandDoc.ml | 13 +++-- infer/src/base/Config.ml | 40 +++++++------ infer/src/infer.ml | 98 +++++++++++++++++--------------- 4 files changed, 102 insertions(+), 85 deletions(-) diff --git a/infer/man/man1/infer-explore.txt b/infer/man/man1/infer-explore.txt index 1de4b0030..41b807f26 100644 --- a/infer/man/man1/infer-explore.txt +++ b/infer/man/man1/infer-explore.txt @@ -4,16 +4,20 @@ NAME SYNOPSIS infer explore [options] infer explore --procedures [options] + infer explore --source-files [options] DESCRIPTION - Show the list of bugs on the console and explore symbolic program - traces emitted by infer to explain a report. Can also generate an HTML - report from a JSON report. - If --procedures is passed, print information about each procedure captured by infer. + If --source-files is passed, print information about captured source + files. + + Otherwise, show the list of bugs on the console and explore symbolic + program traces emitted by infer to explain a report. Can also generate + an HTML report from a JSON report. + OPTIONS @@ -29,6 +33,10 @@ OPTIONS Show this manual with all internal options in the INTERNAL OPTIONS section + --results-dir,-o dir + Write results and internal files in the specified directory + (default: ./infer-out) +EXPLORE BUGS --html Activates: Generate html report. (Conversely: --no-html) @@ -41,6 +49,13 @@ OPTIONS Activates: Show the list of reports and exit (Conversely: --no-only-show) + --select N + Select bug number N. If omitted, prompt for input. + + --no-source-preview + Deactivates: print code excerpts around trace elements + (Conversely: --source-preview) +EXPLORE PROCEDURES --procedures Activates: Print functions and methods discovered by infer (Conversely: --no-procedures) @@ -71,14 +86,7 @@ OPTIONS Deactivates: Include the source file in which the procedure definition or declaration was found in the output of --procedures (Conversely: --procedures-source-file) - - --results-dir,-o dir - Write results and internal files in the specified directory - (default: ./infer-out) - - --select N - Select bug number N. If omitted, prompt for input. - +EXPLORE SOURCE FILES --source-files Activates: Print source files discovered by infer (Conversely: --no-source-files) @@ -109,10 +117,6 @@ OPTIONS output of --source-files (Conversely: --no-source-files-type-environment) - --no-source-preview - Deactivates: print code excerpts around trace elements - (Conversely: --source-preview) - ENVIRONMENT INFER_ARGS, INFERCONFIG, INFER_STRICT_MODE diff --git a/infer/src/base/CommandDoc.ml b/infer/src/base/CommandDoc.ml index 4bc09f7b4..2ad1e1eda 100644 --- a/infer/src/base/CommandDoc.ml +++ b/infer/src/base/CommandDoc.ml @@ -126,14 +126,17 @@ let explore = ~short_description:"explore the error traces in infer reports" ~synopsis: {|$(b,infer) $(b,explore) $(i,[options]) -$(b,infer) $(b,explore) $(b,--procedures) $(i,[options])|} +$(b,infer) $(b,explore) $(b,--procedures) $(i,[options]) +$(b,infer) $(b,explore) $(b,--source-files) $(i,[options])|} ~description: [ `P - "Show the list of bugs on the console and explore symbolic program traces emitted by \ - infer to explain a report. Can also generate an HTML report from a JSON report." - ; `P "If $(b,--procedures) is passed, print information about each procedure captured by \ - infer." ] + infer." + ; `P "If $(b,--source-files) is passed, print information about captured source files." + ; `P + "Otherwise, show the list of bugs on the console and explore symbolic program traces \ + emitted by infer to explain a report. Can also generate an HTML report from a JSON \ + report." ] ~see_also:InferCommand.[Report; Run] diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index a39758513..790c9eafa 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -201,6 +201,12 @@ let manual_clang = "CLANG OPTIONS" let manual_clang_linters = "CLANG LINTERS OPTIONS" +let manual_explore_bugs = "EXPLORE BUGS" + +let manual_explore_procedures = "EXPLORE PROCEDURES" + +let manual_explore_source_files = "EXPLORE SOURCE FILES" + let manual_generic = Cmdliner.Manpage.s_options let manual_hoisting = "HOISTING OPTIONS" @@ -1427,7 +1433,7 @@ and help_format = and html = CLOpt.mk_bool ~long:"html" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_bugs)] "Generate html report." @@ -1608,7 +1614,7 @@ and margin = and max_nesting = CLOpt.mk_int_opt ~long:"max-nesting" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_bugs)] "Level of nested procedure calls to show. Trace elements beyond the maximum nesting level are \ skipped. If omitted, all levels are shown." @@ -1678,7 +1684,7 @@ and only_footprint = and only_show = CLOpt.mk_bool ~long:"only-show" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_bugs)] "Show the list of reports and exit" @@ -1763,19 +1769,19 @@ and print_using_diff = and procedures = CLOpt.mk_bool ~long:"procedures" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_procedures)] "Print functions and methods discovered by infer" and procedures_attributes = CLOpt.mk_bool ~long:"procedures-attributes" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_procedures)] "Print the attributes of each procedure in the output of $(b,--procedures)" and procedures_definedness = CLOpt.mk_bool ~long:"procedures-definedness" ~default:true - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_procedures)] "Include procedures definedness in the output of $(b,--procedures), i.e. whether the \ procedure definition was found, or only the procedure declaration, or the procedure is an \ auto-generated Objective-C accessor" @@ -1783,7 +1789,7 @@ and procedures_definedness = and procedures_filter = CLOpt.mk_string_opt ~long:"procedures-filter" ~meta:"filter" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_procedures)] "With $(b,--procedures), only print functions and methods (procedures) matching the specified \ $(i,filter). A procedure filter is of the form $(i,path_pattern:procedure_name). Patterns \ are interpreted as OCaml Str regular expressions. For instance, to keep only methods named \ @@ -1792,7 +1798,7 @@ and procedures_filter = and procedures_name = CLOpt.mk_bool ~long:"procedures-name" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_procedures)] "Include procedures names in the output of $(b,--procedures)" @@ -1805,7 +1811,7 @@ and procedures_per_process = and procedures_source_file = CLOpt.mk_bool ~long:"procedures-source-file" ~default:true - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_procedures)] "Include the source file in which the procedure definition or declaration was found in the \ output of $(b,--procedures)" @@ -1987,7 +1993,7 @@ and seconds_per_iteration = and select = CLOpt.mk_int_opt ~long:"select" ~meta:"N" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_bugs)] "Select bug number $(i,N). If omitted, prompt for input." @@ -2025,19 +2031,19 @@ and skip_translation_headers = and source_preview = CLOpt.mk_bool ~long:"source-preview" ~default:true - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_bugs)] "print code excerpts around trace elements" and source_files = CLOpt.mk_bool ~long:"source-files" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_source_files)] "Print source files discovered by infer" and source_files_cfg = CLOpt.mk_bool ~long:"source-files-cfg" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_source_files)] (Printf.sprintf "Output a dotty file in infer-out/%s for each source file in the output of \ $(b,--source-files)" @@ -2046,7 +2052,7 @@ and source_files_cfg = and source_files_filter = CLOpt.mk_string_opt ~long:"source-files-filter" ~meta:"filter" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_source_files)] "With $(b,--source-files), only print source files matching the specified $(i,filter). The \ filter is a pattern that should match the file path. Patterns are interpreted as OCaml Str \ regular expressions." @@ -2054,19 +2060,19 @@ and source_files_filter = and source_files_type_environment = CLOpt.mk_bool ~long:"source-files-type-environment" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_source_files)] "Print the type environment of each source file in the output of $(b,--source-files)" and source_files_procedure_names = CLOpt.mk_bool ~long:"source-files-procedure-names" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_source_files)] "Print the names of procedure of each source file in the output of $(b,--source-files)" and source_files_freshly_captured = CLOpt.mk_bool ~long:"source-files-freshly-captured" - ~in_help:InferCommand.[(Explore, manual_generic)] + ~in_help:InferCommand.[(Explore, manual_explore_source_files)] "Print whether the source file has been captured in the most recent capture phase in the \ output of $(b,--source-files)." diff --git a/infer/src/infer.ml b/infer/src/infer.ml index fbf1212fd..a83e97ceb 100644 --- a/infer/src/infer.ml +++ b/infer/src/infer.ml @@ -145,53 +145,57 @@ let () = ~previous_costs:Config.costs_previous | Diff -> Diff.diff (Lazy.force Driver.mode_from_command_line) - | Explore when Config.procedures -> - L.result "%a" - Config.( - Procedures.pp_all - ~filter:(Lazy.force Filtering.procedures_filter) - ~proc_name:procedures_name ~attr_kind:procedures_definedness - ~source_file:procedures_source_file ~proc_attributes:procedures_attributes) - () - | Explore when Config.source_files -> - let filter = Lazy.force Filtering.source_files_filter in - L.result "%a" - (SourceFiles.pp_all ~filter ~type_environment:Config.source_files_type_environment - ~procedure_names:Config.source_files_procedure_names - ~freshly_captured:Config.source_files_freshly_captured) - () ; - if Config.source_files_cfg then ( - let source_files = SourceFiles.get_all ~filter () in - List.iter source_files ~f:(fun source_file -> - (* create directory in captured/ *) - DB.Results_dir.init ~debug:true source_file ; - (* collect the CFGs for all the procedures in [source_file] *) - let proc_names = SourceFiles.proc_names_of_source source_file in - let cfgs = Typ.Procname.Hash.create (List.length proc_names) in - List.iter proc_names ~f:(fun proc_name -> - Procdesc.load proc_name - |> Option.iter ~f:(fun cfg -> Typ.Procname.Hash.add cfgs proc_name cfg) ) ; - (* emit the dotty file in captured/... *) - Dotty.print_icfg_dotty source_file cfgs ) ; - L.result "CFGs written in %s/*/%s@." Config.captured_dir Config.dotty_output ) - | Explore -> - let if_some key opt args = - match opt with None -> args | Some arg -> key :: string_of_int arg :: args - in - let if_true key opt args = if not opt then args else key :: args in - let if_false key opt args = if opt then args else key :: args in - let args = - if_some "--max-level" Config.max_nesting - @@ if_true "--only-show" Config.only_show - @@ if_false "--no-source" Config.source_preview - @@ if_true "--html" Config.html - @@ if_some "--select" Config.select ["-o"; Config.results_dir] - in - let prog = Config.lib_dir ^/ "python" ^/ "inferTraceBugs" in - if is_error (Unix.waitpid (Unix.fork_exec ~prog ~argv:(prog :: args) ())) then - L.external_error - "** Error running the reporting script:@\n** %s %s@\n** See error above@." prog - (String.concat ~sep:" " args) + | Explore -> ( + match (Config.procedures, Config.source_files) with + | true, false -> + L.result "%a" + Config.( + Procedures.pp_all + ~filter:(Lazy.force Filtering.procedures_filter) + ~proc_name:procedures_name ~attr_kind:procedures_definedness + ~source_file:procedures_source_file ~proc_attributes:procedures_attributes) + () + | false, true -> + let filter = Lazy.force Filtering.source_files_filter in + L.result "%a" + (SourceFiles.pp_all ~filter ~type_environment:Config.source_files_type_environment + ~procedure_names:Config.source_files_procedure_names + ~freshly_captured:Config.source_files_freshly_captured) + () ; + if Config.source_files_cfg then ( + let source_files = SourceFiles.get_all ~filter () in + List.iter source_files ~f:(fun source_file -> + (* create directory in captured/ *) + DB.Results_dir.init ~debug:true source_file ; + (* collect the CFGs for all the procedures in [source_file] *) + let proc_names = SourceFiles.proc_names_of_source source_file in + let cfgs = Typ.Procname.Hash.create (List.length proc_names) in + List.iter proc_names ~f:(fun proc_name -> + Procdesc.load proc_name + |> Option.iter ~f:(fun cfg -> Typ.Procname.Hash.add cfgs proc_name cfg) ) ; + (* emit the dotty file in captured/... *) + Dotty.print_icfg_dotty source_file cfgs ) ; + L.result "CFGs written in %s/*/%s@." Config.captured_dir Config.dotty_output ) + | false, false -> + let if_some key opt args = + match opt with None -> args | Some arg -> key :: string_of_int arg :: args + in + let if_true key opt args = if not opt then args else key :: args in + let if_false key opt args = if opt then args else key :: args in + let args = + if_some "--max-level" Config.max_nesting + @@ if_true "--only-show" Config.only_show + @@ if_false "--no-source" Config.source_preview + @@ if_true "--html" Config.html + @@ if_some "--select" Config.select ["-o"; Config.results_dir] + in + let prog = Config.lib_dir ^/ "python" ^/ "inferTraceBugs" in + if is_error (Unix.waitpid (Unix.fork_exec ~prog ~argv:(prog :: args) ())) then + L.external_error + "** Error running the reporting script:@\n** %s %s@\n** See error above@." prog + (String.concat ~sep:" " args) + | true, true -> + L.user_error "Options --procedures and --source-files cannot be used together.@\n" ) | Events -> EventLogger.dump () ) ; (* to make sure the exitcode=0 case is logged, explicitly invoke exit *)