[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
master
Nikos Gorogiannis 5 years ago committed by Facebook Github Bot
parent 3653c68c8e
commit 34315ec438

@ -52,16 +52,20 @@ let read_package_declaration source_file =
Utils.with_file_in path ~f:loop |> Option.value ~default:"" 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 = 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 in
fun path map ->
let basename = Filename.basename path in let basename = Filename.basename path in
let entry = let entry =
let current_source_file = SourceFile.from_abs_path (convert_to_absolute path) in let current_source_file = SourceFile.from_abs_path (convert_to_absolute path) in
try match String.Map.find map basename with
match String.Map.find_exn map basename with | None ->
| Singleton previous_source_file -> (* 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. (* Another source file with the same base name has been found.
Reading the package from the source file to resolve the ambiguity Reading the package from the source file to resolve the ambiguity
only happens in this case *) only happens in this case *)
@ -71,24 +75,19 @@ let add_source_file path map =
[(current_package, current_source_file); (previous_package, previous_source_file)] [(current_package, current_source_file); (previous_package, previous_source_file)]
in in
Duplicate source_list 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 *) (* Two or more source file with the same base name have been found *)
let current_package = read_package_declaration current_source_file in let current_package = read_package_declaration current_source_file in
Duplicate ((current_package, current_source_file) :: previous_source_files) 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 in
String.Map.set ~key:basename ~data:entry map String.Map.set ~key:basename ~data:entry map
let add_root_path path roots = String.Set.add roots path let add_root_path path roots = String.Set.add roots path
let load_from_verbose_output javac_verbose_out = let load_from_verbose_output =
let file_in = In_channel.create javac_verbose_out in
let class_filename_re = let class_filename_re =
Str.regexp Printf.sprintf
(Printf.sprintf
(* the unreadable regexp below captures 3 possible forms: (* 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 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 2. [wrote RegularFileObject[path/to/File.java]], leaves `path/to/File.java` in match group 5
@ -96,20 +95,19 @@ let load_from_verbose_output javac_verbose_out =
4. [wrote path/to/File.java] leaves `path/to/File.java` in match group 6 (from java 11)*) 4. [wrote path/to/File.java] leaves `path/to/File.java` in match group 6 (from java 11)*)
"\\[wrote \ "\\[wrote \
\\(DirectoryFileObject\\[%s:\\(.*\\)\\|\\(\\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\)\\]\\|\\(.*\\)\\)\\]" \\(DirectoryFileObject\\[%s:\\(.*\\)\\|\\(\\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\)\\]\\|\\(.*\\)\\)\\]"
Config.javac_classes_out) Config.javac_classes_out
|> Str.regexp
in in
let source_filename_re = let source_filename_re =
Str.regexp "\\[parsing started \\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\]\\]" Str.regexp "\\[parsing started \\(Regular\\|Simple\\)FileObject\\[\\(.*\\)\\]\\]"
in in
let classpath_re = Str.regexp "\\[search path for class files: \\(.*\\)\\]" in let classpath_re = Str.regexp "\\[search path for class files: \\(.*\\)\\]" in
let rec loop paths roots sources classes = let rec loop paths roots sources classes file_in =
match In_channel.input_line_exn file_in with match In_channel.input_line file_in with
| exception End_of_file -> | None ->
In_channel.close file_in ;
let classpath = classpath_of_paths (String.Set.elements roots @ paths) in let classpath = classpath_of_paths (String.Set.elements roots @ paths) in
{classpath; sources; classes} {classpath; sources; classes}
| line -> | Some line when Str.string_match class_filename_re line 0 -> (
if Str.string_match class_filename_re line 0 then
let path = let path =
try Str.matched_group 5 line try Str.matched_group 5 line
with Caml.Not_found -> ( with Caml.Not_found -> (
@ -120,24 +118,27 @@ let load_from_verbose_output javac_verbose_out =
in in
match Javalib.extract_class_name_from_file path with match Javalib.extract_class_name_from_file path with
| exception (JBasics.Class_structure_error _ | Invalid_argument _) -> | exception (JBasics.Class_structure_error _ | Invalid_argument _) ->
(loop [@tailcall]) paths roots sources classes loop paths roots sources classes file_in
| cn, root_info -> | cn, root_info ->
let root_dir = let root_dir =
if String.equal root_info "" then Filename.current_dir_name else root_info if String.equal root_info "" then Filename.current_dir_name else root_info
in in
(loop [@tailcall]) paths (add_root_path root_dir roots) sources loop paths (add_root_path root_dir roots) sources (JBasics.ClassSet.add cn classes)
(JBasics.ClassSet.add cn classes) file_in )
else if Str.string_match source_filename_re line 0 then | Some line when Str.string_match source_filename_re line 0 ->
let path = Str.matched_group 2 line in let path = Str.matched_group 2 line in
(loop [@tailcall]) paths roots (add_source_file path sources) classes loop paths roots (add_source_file path sources) classes file_in
else if Str.string_match classpath_re line 0 then | Some line when Str.string_match classpath_re line 0 ->
let classpath = Str.matched_group 1 line in let classpath = Str.matched_group 1 line in
let parsed_paths = String.split ~on:',' classpath in let parsed_paths = String.split ~on:',' classpath in
(loop [@tailcall]) parsed_paths roots sources classes loop parsed_paths roots sources classes file_in
else (* skip this line *) | _ ->
(loop [@tailcall]) paths roots sources classes (* skip this line *)
loop paths roots sources classes file_in
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 = 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 roots, classes = search_classes classes_out_path in
let split cp_option = Option.value_map ~f:split_classpath ~default:[] cp_option in let split cp_option = Option.value_map ~f:split_classpath ~default:[] cp_option in
let classpath = 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 split Config.bootclasspath @ split Config.classpath @ String.Set.elements roots
|> classpath_of_paths |> classpath_of_paths
in in

@ -89,18 +89,18 @@ let do_all_files sources program =
is_path_matching (SourceFile.to_rel_path source_file) is_path_matching (SourceFile.to_rel_path source_file)
|| Inferconfig.skip_translation_matcher source_file Procname.empty_block || Inferconfig.skip_translation_matcher source_file Procname.empty_block
in 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 if not (skip source_file) then do_source_file program tenv basename package_opt source_file
in in
String.Map.iteri String.Map.iteri
~f:(fun ~key:basename ~data:file_entry -> ~f:(fun ~key:basename ~data:file_entry ->
match file_entry with match file_entry with
| JClasspath.Singleton source_file -> | JClasspath.Singleton source_file ->
translate_source_file basename (None, source_file) source_file translate_source_file basename None source_file
| JClasspath.Duplicate source_files -> | JClasspath.Duplicate source_files ->
List.iter List.iter
~f:(fun (package, source_file) -> ~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 ) source_files )
sources ; sources ;
if Config.dependency_mode then capture_libs program tenv ; if Config.dependency_mode then capture_libs program tenv ;

Loading…
Cancel
Save