diff --git a/infer/man/man1/infer-full.txt b/infer/man/man1/infer-full.txt index bf002f9db..9dd58aa63 100644 --- a/infer/man/man1/infer-full.txt +++ b/infer/man/man1/infer-full.txt @@ -1431,6 +1431,13 @@ INTERNAL OPTIONS expressed as a multiple of symbolic operations and a multiple of seconds of elapsed time + --java-debug-source-file-info path + For debugging only: Call the Java declarations source file parser + on the given file and do not run anything else. + + --java-debug-source-file-info-reset + Cancel the effect of --java-debug-source-file-info. + --java-jar-compiler-reset Cancel the effect of --java-jar-compiler. diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 7af2481de..a33af2ac3 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -1396,6 +1396,12 @@ and iterations = symbolic operations and a multiple of seconds of elapsed time" +and java_debug_source_file_info = + CLOpt.mk_path_opt ~long:"java-debug-source-file-info" ~meta:"path" + "For debugging only: Call the Java declarations source file parser on the given file and do \ + not run anything else." + + and java_jar_compiler = CLOpt.mk_path_opt ~long:"java-jar-compiler" ~in_help:InferCommand.[(Capture, manual_java)] @@ -2737,6 +2743,8 @@ and issues_tests_fields = !issues_tests_fields and iterations = !iterations +and java_debug_source_file_info = !java_debug_source_file_info + and java_jar_compiler = !java_jar_compiler and java_version = !java_version diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index f94b91d20..b714de432 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -344,6 +344,8 @@ val issues_tests_fields : IssuesTestField.t list val iterations : int +val java_debug_source_file_info : string option + val java_jar_compiler : string option val java_version : int option diff --git a/infer/src/dune.in b/infer/src/dune.in index 2153afd83..d5962c21f 100644 --- a/infer/src/dune.in +++ b/infer/src/dune.in @@ -63,12 +63,13 @@ let infer_exe_stanza = (name infer) (modes byte_complete exe) (modules Infer) - (flags (:standard -open Core -open IStdlib -open IStd -open IBase -open IR -open Backend -open Integration -open Biabduction -open TestDeterminators -open ClangFrontend -open ASTLanguage %s)) + (flags (:standard -open Core -open IStdlib -open IStd -open IBase -open IR -open Backend -open Integration -open Biabduction -open TestDeterminators -open ClangFrontend -open ASTLanguage %s -open JavaFrontend %s)) (libraries %s core IStdlib IBase IR Backend Integration Biabduction TestDeterminators ClangFrontend ASTLanguage) (preprocess (pps ppx_compare)) (promote (until-clean) (into ../bin)) )|} (if clang then "" else "-open ClangFrontendStubs") + (if java then "" else "-open JavaFrontendStubs") extlib_if_java diff --git a/infer/src/infer.ml b/infer/src/infer.ml index 5bae0b612..6832bc138 100644 --- a/infer/src/infer.ml +++ b/infer/src/infer.ml @@ -136,87 +136,87 @@ let () = if Config.debug_mode && CLOpt.is_originator then ( L.progress "Logs in %s@." (ResultsDir.get_path Logs) ; L.progress "Execution ID %Ld@." Config.execution_id ) ; - ( if Config.test_determinator && not Config.process_clang_ast then - TestDeterminator.compute_and_emit_test_to_run () - else - match Config.command with - | Analyze -> - run Driver.Analyze - | Capture | Compile | Run -> - run (Lazy.force Driver.mode_from_command_line) - | Report -> ( - match Config.issues_tests with - | None -> - if not Config.quiet then L.result "%t" SpecsFiles.pp_from_config - | Some out_path -> - IssuesTest.write_from_json ~json_path:Config.from_json_report ~out_path - Config.issues_tests_fields ) - | ReportDiff -> - (* at least one report must be passed in input to compute differential *) - ( match Config.(report_current, report_previous, costs_current, costs_previous) with - | None, None, None, None -> - L.(die UserError) - "Expected at least one argument among '--report-current', '--report-previous', \ - '--costs-current', and '--costs-previous'" - | _ -> - () ) ; - ReportDiff.reportdiff ~current_report:Config.report_current - ~previous_report:Config.report_previous ~current_costs:Config.costs_current - ~previous_costs:Config.costs_previous - | Explore -> ( - match (Config.procedures, Config.source_files) with - | true, false -> - let filter = Lazy.force Filtering.procedures_filter in - if Config.procedures_summary then - let pp_summary fmt proc_name = - match Summary.OnDisk.get proc_name with - | None -> - Format.fprintf fmt "No summary found: %a@\n" Procname.pp proc_name - | Some summary -> - Summary.pp_text fmt summary - in - Option.iter (Procedures.select_proc_names_interactive ~filter) ~f:(fun proc_names -> - L.result "%a" (fun fmt () -> List.iter proc_names ~f:(pp_summary fmt)) () ) - else - L.result "%a" - Config.( - Procedures.pp_all ~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 + ( match Config.command with + | _ when Config.test_determinator && not Config.process_clang_ast -> + TestDeterminator.compute_and_emit_test_to_run () + | _ when Option.is_some Config.java_debug_source_file_info -> + JSourceFileInfo.debug_on_file (Option.value_exn Config.java_debug_source_file_info) + | Analyze -> + run Driver.Analyze + | Capture | Compile | Run -> + run (Lazy.force Driver.mode_from_command_line) + | Report -> ( + match Config.issues_tests with + | None -> + if not Config.quiet then L.result "%t" SpecsFiles.pp_from_config + | Some out_path -> + IssuesTest.write_from_json ~json_path:Config.from_json_report ~out_path + Config.issues_tests_fields ) + | ReportDiff -> + (* at least one report must be passed in input to compute differential *) + ( match Config.(report_current, report_previous, costs_current, costs_previous) with + | None, None, None, None -> + L.die UserError + "Expected at least one argument among '--report-current', '--report-previous', \ + '--costs-current', and '--costs-previous'" + | _ -> + () ) ; + ReportDiff.reportdiff ~current_report:Config.report_current + ~previous_report:Config.report_previous ~current_costs:Config.costs_current + ~previous_costs:Config.costs_previous + | Explore -> ( + match (Config.procedures, Config.source_files) with + | true, false -> + let filter = Lazy.force Filtering.procedures_filter in + if Config.procedures_summary then + let pp_summary fmt proc_name = + match Summary.OnDisk.get proc_name with + | None -> + Format.fprintf fmt "No summary found: %a@\n" Procname.pp proc_name + | Some summary -> + Summary.pp_text fmt summary + in + Option.iter (Procedures.select_proc_names_interactive ~filter) ~f:(fun proc_names -> + L.result "%a" (fun fmt () -> List.iter proc_names ~f:(pp_summary fmt)) () ) + else 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 = 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 -> Procname.Hash.add cfgs proc_name cfg) ) ; - (* emit the dot file in captured/... *) - DotCfg.emit_frontend_cfg source_file cfgs ) ; - L.result "CFGs written in %s/*/%s@." (ResultsDir.get_path Debug) - Config.dotty_frontend_output ) - | false, false -> - (* explore bug traces *) - if Config.html then - TraceBugs.gen_html_report ~report_json:(ResultsDir.get_path ReportJson) - ~show_source_context:Config.source_preview ~max_nested_level:Config.max_nesting - ~report_html_dir:(ResultsDir.get_path ReportHtml) - else - TraceBugs.explore ~selector_limit:None ~report_json:(ResultsDir.get_path ReportJson) - ~report_txt:(ResultsDir.get_path ReportText) ~selected:Config.select - ~show_source_context:Config.source_preview ~max_nested_level:Config.max_nesting - | true, true -> - L.user_error "Options --procedures and --source-files cannot be used together.@\n" ) ) ; + Config.( + Procedures.pp_all ~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 = 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 -> Procname.Hash.add cfgs proc_name cfg) ) ; + (* emit the dot file in captured/... *) + DotCfg.emit_frontend_cfg source_file cfgs ) ; + L.result "CFGs written in %s/*/%s@." (ResultsDir.get_path Debug) + Config.dotty_frontend_output ) + | false, false -> + (* explore bug traces *) + if Config.html then + TraceBugs.gen_html_report ~report_json:(ResultsDir.get_path ReportJson) + ~show_source_context:Config.source_preview ~max_nested_level:Config.max_nesting + ~report_html_dir:(ResultsDir.get_path ReportHtml) + else + TraceBugs.explore ~selector_limit:None ~report_json:(ResultsDir.get_path ReportJson) + ~report_txt:(ResultsDir.get_path ReportText) ~selected:Config.select + ~show_source_context:Config.source_preview ~max_nested_level:Config.max_nesting + | true, true -> + L.user_error "Options --procedures and --source-files cannot be used together.@\n" ) ) ; (* to make sure the exitcode=0 case is logged, explicitly invoke exit *) L.exit 0 diff --git a/infer/src/java/JavaFrontendStubs.ml b/infer/src/java/JavaFrontendStubs.ml index f265f2bdc..3871b9c35 100644 --- a/infer/src/java/JavaFrontendStubs.ml +++ b/infer/src/java/JavaFrontendStubs.ml @@ -12,3 +12,7 @@ module JMain = struct let from_verbose_out _ = () end + +module JSourceFileInfo = struct + let debug_on_file _ = () +end diff --git a/infer/src/java/JavaFrontendStubs.mli b/infer/src/java/JavaFrontendStubs.mli index c650460f9..83fcde890 100644 --- a/infer/src/java/JavaFrontendStubs.mli +++ b/infer/src/java/JavaFrontendStubs.mli @@ -15,8 +15,10 @@ open! IStd module JMain : sig val from_arguments : string -> unit - (** loads the source files from command line arguments and translates them *) val from_verbose_out : string -> unit - (** loads the source files from javac's verbose output translates them *) +end + +module JSourceFileInfo : sig + val debug_on_file : string -> unit end diff --git a/infer/src/java/jSourceFileInfo.mll b/infer/src/java/jSourceFileInfo.mll index 9a7924966..163ee9b28 100644 --- a/infer/src/java/jSourceFileInfo.mll +++ b/infer/src/java/jSourceFileInfo.mll @@ -401,4 +401,8 @@ and skip_comments action = parse (SourceFile.to_abs_path file); In_channel.close cin ) + + let debug_on_file _path = + (* TODO: do something here *) + () }