From 185e7f713111f370c2b1b8a71b2236e1a3b89e21 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Mon, 30 Oct 2017 10:28:51 -0700 Subject: [PATCH] [java] support Java9 Summary: Support `javac` invocations from Java9. closes #774 Reviewed By: jeremydubreil Differential Revision: D6135103 fbshipit-source-id: a57ea5c --- infer/models/java/Makefile | 2 +- infer/src/base/Config.ml | 7 ++++++- infer/src/base/Config.mli | 2 +- infer/src/integration/Javac.ml | 13 +------------ infer/src/java/jClasspath.ml | 26 +++++++++++++++++++++----- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/infer/models/java/Makefile b/infer/models/java/Makefile index 5d5b61395..2487b7945 100644 --- a/infer/models/java/Makefile +++ b/infer/models/java/Makefile @@ -34,7 +34,7 @@ $(INFER_REPORT): $(JAVA_DEPS_NO_MODELS) $(JAVA_SOURCES) $(MAKEFILE_LIST) $(QUIET)$(call silent_on_success,Building Java models,\ $(INFER_BIN) -a checkers --biabduction-only --results-dir $(INFER_RESULTS_DIR) --models-mode -- \ $(JAVAC) -bootclasspath $(ANDROID_JAR) -d $(MODELS_OUT) -classpath $(MODELS_CLASSPATH) \ - $(JAVA_SOURCES)) + $(JAVA_SOURCES) -source 7 -target 7) $(MODELS_JAR): $(INFER_REPORT) cd $(MODELS_OUT); jar cf ../$(MODELS_JAR) * diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index c912c62f0..f28614d8d 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -2005,7 +2005,12 @@ and xml_specs = are allowed to refer to the other arg variables. *) let javac_classes_out = - CLOpt.mk_string_opt ~parse_mode:CLOpt.Javac ~deprecated:["classes_out"] ~long:"" ~short:'d' + CLOpt.mk_string ~parse_mode:CLOpt.Javac ~deprecated:["classes_out"] ~long:"" + ~short: + 'd' + (* Ensure that some form of "-d ..." is passed to javac. It's unclear whether this is strictly + needed but the tests break without this for now. See discussion in D4397716. *) + ~default:CLOpt.init_work_dir ~f:(fun classes_out -> ( if !buck then let classes_out_infer = resolve classes_out ^/ buck_results_dir_name in diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 183321381..4aa98401b 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -490,7 +490,7 @@ val iterations : int val java_jar_compiler : string option -val javac_classes_out : string option +val javac_classes_out : string val javac_verbose_out : string diff --git a/infer/src/integration/Javac.ml b/infer/src/integration/Javac.ml index afb9a7e62..c6fa3dda4 100644 --- a/infer/src/integration/Javac.ml +++ b/infer/src/integration/Javac.ml @@ -26,18 +26,7 @@ let compile compiler build_prog build_args = ("java", ["-jar"; jar]) in let cli_args, file_args = - let args = - "-verbose" - :: "-g" - :: - (* Ensure that some form of "-d ..." is passed to javac. It's unclear whether this is strictly - needed but the tests break without this for now. See discussion in D4397716. *) - ( match Config.javac_classes_out with - | Some _ -> - build_args - | None -> - "-d" :: CLOpt.init_work_dir :: build_args ) - in + let args = "-verbose" :: "-g" :: "-d" :: Config.javac_classes_out :: build_args in List.partition_tf args ~f:(fun arg -> (* As mandated by javac, argument files must not contain certain arguments. *) String.is_prefix ~prefix:"-J" arg || String.is_prefix ~prefix:"@" arg ) diff --git a/infer/src/java/jClasspath.ml b/infer/src/java/jClasspath.ml index d77c30f46..c7390a984 100644 --- a/infer/src/java/jClasspath.ml +++ b/infer/src/java/jClasspath.ml @@ -142,25 +142,41 @@ let add_root_path path roots = String.Set.add roots path let load_from_verbose_output javac_verbose_out = let file_in = In_channel.create javac_verbose_out in - let class_filename_re = Str.regexp "\\[wrote RegularFileObject\\[\\(.*\\)\\]\\]" in - let source_filename_re = Str.regexp "\\[parsing started RegularFileObject\\[\\(.*\\)\\]\\]" in + let class_filename_re = + Str.regexp + (Printf.sprintf + (* the unreadable regexp below captures 3 possible forms: + 1. [wrote DirectoryFileObject[/path/to/classes_out:path/to/File.java]], leaves `path/to/File.java` in match group 2 + 2. [wrote RegularFileObject[path/to/File.java]], leaves `path/to/File.java` in match group 5 + 3. [wrote SimpleFileObject[path/to/File.java]], also leaves `path/to/File.java` in match group 5 *) + "\\[wrote \\(DirectoryFileObject\\[%s:\\(.*\\)\\|\\(\\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\)\\)\\]\\]" + Config.javac_classes_out) + in + let source_filename_re = + Str.regexp "\\[parsing started \\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\]\\]" + in let classpath_re = Str.regexp "\\[search path for class files: \\(.*\\)\\]" in let rec loop paths roots sources classes = try let line = In_channel.input_line_exn file_in in if Str.string_match class_filename_re line 0 then - let path = Str.matched_group 1 line in + let path = + try Str.matched_group 5 line + with Not_found -> + (* either matched group 5 is found, or matched group 2 is found, see doc for [class_filename_re] above *) + Config.javac_classes_out ^/ Str.matched_group 2 line + in let cn, root_info = Javalib.extract_class_name_from_file path in let root_dir = if String.equal root_info "" then Filename.current_dir_name else root_info in loop paths (add_root_path root_dir roots) sources (JBasics.ClassSet.add cn classes) else if Str.string_match source_filename_re line 0 then - let path = Str.matched_group 1 line in + let path = Str.matched_group 2 line in loop paths roots (add_source_file path sources) classes else if Str.string_match classpath_re line 0 then let classpath = Str.matched_group 1 line in - let parsed_paths = Str.split (Str.regexp_string ",") classpath in + let parsed_paths = String.split ~on:',' classpath in loop parsed_paths roots sources classes else (* skip this line *) loop paths roots sources classes