From 34315ec4384d093f93d4ecfbfa6dff43145bd012 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Mon, 9 Mar 2020 02:26:45 -0700 Subject: [PATCH] [java] classpath and frontend fixes Summary: - Remove dead argument in function in JMain. - Document order of constructed classpath. - Stop asking repeatedly for the cwd in `add_source_file`. - Improve exception safety and readability in `load_from_verbose_output`. Reviewed By: ezgicicek Differential Revision: D20290519 fbshipit-source-id: 86c32dcdf --- infer/src/java/jClasspath.ml | 120 ++++++++++++++++++----------------- infer/src/java/jMain.ml | 6 +- 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/infer/src/java/jClasspath.ml b/infer/src/java/jClasspath.ml index 6374250b1..1b83abdbe 100644 --- a/infer/src/java/jClasspath.ml +++ b/infer/src/java/jClasspath.ml @@ -52,16 +52,20 @@ let read_package_declaration source_file = Utils.with_file_in path ~f:loop |> Option.value ~default:"" -let add_source_file path map = +let add_source_file = + let cwd = lazy (Sys.getcwd ()) in let convert_to_absolute p = - if Filename.is_relative p then Filename.concat (Sys.getcwd ()) p else p + if Filename.is_relative p then Filename.concat (Lazy.force cwd) p else p in - let basename = Filename.basename path in - let entry = - let current_source_file = SourceFile.from_abs_path (convert_to_absolute path) in - try - match String.Map.find_exn map basename with - | Singleton previous_source_file -> + fun path map -> + let basename = Filename.basename path in + let entry = + let current_source_file = SourceFile.from_abs_path (convert_to_absolute path) in + match String.Map.find map basename with + | None -> + (* Most common case: there is no conflict with the base name of the source file *) + Singleton current_source_file + | Some (Singleton previous_source_file) -> (* Another source file with the same base name has been found. Reading the package from the source file to resolve the ambiguity only happens in this case *) @@ -71,73 +75,70 @@ let add_source_file path map = [(current_package, current_source_file); (previous_package, previous_source_file)] in Duplicate source_list - | Duplicate previous_source_files -> + | Some (Duplicate previous_source_files) -> (* Two or more source file with the same base name have been found *) let current_package = read_package_declaration current_source_file in Duplicate ((current_package, current_source_file) :: previous_source_files) - with Not_found_s _ | Caml.Not_found -> - (* Most common case: there is no conflict with the base name of the source file *) - Singleton current_source_file - in - String.Map.set ~key:basename ~data:entry map + in + String.Map.set ~key:basename ~data:entry map 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 load_from_verbose_output = 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 - 4. [wrote path/to/File.java] leaves `path/to/File.java` in match group 6 (from java 11)*) - "\\[wrote \ - \\(DirectoryFileObject\\[%s:\\(.*\\)\\|\\(\\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\)\\]\\|\\(.*\\)\\)\\]" - Config.javac_classes_out) + 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 + 4. [wrote path/to/File.java] leaves `path/to/File.java` in match group 6 (from java 11)*) + "\\[wrote \ + \\(DirectoryFileObject\\[%s:\\(.*\\)\\|\\(\\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\)\\]\\|\\(.*\\)\\)\\]" + Config.javac_classes_out + |> Str.regexp 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 = - match In_channel.input_line_exn file_in with - | exception End_of_file -> - In_channel.close file_in ; + let rec loop paths roots sources classes file_in = + match In_channel.input_line file_in with + | None -> let classpath = classpath_of_paths (String.Set.elements roots @ paths) in {classpath; sources; classes} - | line -> - if Str.string_match class_filename_re line 0 then - let path = - try Str.matched_group 5 line - with Caml.Not_found -> ( - try Config.javac_classes_out ^/ Str.matched_group 2 line - with Caml.Not_found -> - (* either matched group 5, 6, or 2 is found, see doc for [class_filename_re] above *) - Str.matched_group 6 line ) - in - match Javalib.extract_class_name_from_file path with - | exception (JBasics.Class_structure_error _ | Invalid_argument _) -> - (loop [@tailcall]) paths roots sources classes - | cn, root_info -> - let root_dir = - if String.equal root_info "" then Filename.current_dir_name else root_info - in - (loop [@tailcall]) 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 2 line in - (loop [@tailcall]) 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 = String.split ~on:',' classpath in - (loop [@tailcall]) parsed_paths roots sources classes - else (* skip this line *) - (loop [@tailcall]) paths roots sources classes + | Some line when Str.string_match class_filename_re line 0 -> ( + let path = + try Str.matched_group 5 line + with Caml.Not_found -> ( + try Config.javac_classes_out ^/ Str.matched_group 2 line + with Caml.Not_found -> + (* either matched group 5, 6, or 2 is found, see doc for [class_filename_re] above *) + Str.matched_group 6 line ) + in + match Javalib.extract_class_name_from_file path with + | exception (JBasics.Class_structure_error _ | Invalid_argument _) -> + loop paths roots sources classes file_in + | cn, root_info -> + 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) + file_in ) + | Some line when Str.string_match source_filename_re line 0 -> + let path = Str.matched_group 2 line in + loop paths roots (add_source_file path sources) classes file_in + | Some line when Str.string_match classpath_re line 0 -> + let classpath = Str.matched_group 1 line in + let parsed_paths = String.split ~on:',' classpath in + loop parsed_paths roots sources classes file_in + | _ -> + (* skip this line *) + loop paths roots sources classes file_in in - loop [] String.Set.empty String.Map.empty JBasics.ClassSet.empty + fun javac_verbose_out -> + Utils.with_file_in javac_verbose_out + ~f:(loop [] String.Set.empty String.Map.empty JBasics.ClassSet.empty) let collect_classnames init jar_filename = @@ -187,6 +188,7 @@ let load_from_arguments classes_out_path = let roots, classes = search_classes classes_out_path in let split cp_option = Option.value_map ~f:split_classpath ~default:[] cp_option in let classpath = + (* order follows https://docs.oracle.com/javase/7/docs/technotes/tools/windows/classpath.html *) split Config.bootclasspath @ split Config.classpath @ String.Set.elements roots |> classpath_of_paths in diff --git a/infer/src/java/jMain.ml b/infer/src/java/jMain.ml index 14439d9bc..3c0b0cfa3 100644 --- a/infer/src/java/jMain.ml +++ b/infer/src/java/jMain.ml @@ -89,18 +89,18 @@ let do_all_files sources program = is_path_matching (SourceFile.to_rel_path source_file) || Inferconfig.skip_translation_matcher source_file Procname.empty_block in - let translate_source_file basename (package_opt, _) source_file = + let translate_source_file basename package_opt source_file = if not (skip source_file) then do_source_file program tenv basename package_opt source_file in String.Map.iteri ~f:(fun ~key:basename ~data:file_entry -> match file_entry with | JClasspath.Singleton source_file -> - translate_source_file basename (None, source_file) source_file + translate_source_file basename None source_file | JClasspath.Duplicate source_files -> List.iter ~f:(fun (package, source_file) -> - translate_source_file basename (Some package, source_file) source_file ) + translate_source_file basename (Some package) source_file ) source_files ) sources ; if Config.dependency_mode then capture_libs program tenv ;