[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:""
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

@ -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 ;

Loading…
Cancel
Save