diff --git a/infer/src/backend/printer.ml b/infer/src/backend/printer.ml index 40385a033..a2b10398b 100644 --- a/infer/src/backend/printer.ml +++ b/infer/src/backend/printer.ml @@ -14,56 +14,6 @@ module Hashtbl = Caml.Hashtbl module L = Logging module F = Format -(** Module to read specific lines from files. The data from any file will stay in memory until the - handle is collected by the gc. *) -module LineReader = struct - (** Map a file name to an array of string, one for each line in the file. *) - type t = (SourceFile.t, string array) Hashtbl.t - - let create () = Hashtbl.create 1 - - let read_file fname = - let cin = In_channel.create fname in - let lines = ref [] in - try - while true do - let line_raw = In_channel.input_line_exn cin in - let line = - let len = String.length line_raw in - if len > 0 && Char.equal line_raw.[len - 1] '\r' then - String.sub line_raw ~pos:0 ~len:(len - 1) - else line_raw - in - lines := line :: !lines - done ; - assert false (* execution never reaches here *) - with End_of_file -> In_channel.close cin ; Array.of_list_rev !lines - - - let file_data (hash : t) fname = - try Some (Hashtbl.find hash fname) - with Caml.Not_found -> ( - try - let lines_arr = read_file (SourceFile.to_abs_path fname) in - Hashtbl.add hash fname lines_arr ; Some lines_arr - with exn when SymOp.exn_not_failure exn -> None ) - - - let from_file_linenum hash fname linenum = - match file_data hash fname with - | Some lines_arr when linenum > 0 && linenum <= Array.length lines_arr -> - Some lines_arr.(linenum - 1) - | _ -> - None - - - let from_loc hash loc = from_file_linenum hash loc.Location.file loc.Location.line - - let iter hash fname ~f = - file_data hash fname - |> Option.iter ~f:(Array.iteri ~f:(fun linenum line -> f (linenum + 1) line)) -end - (** Current formatter for the html output *) let curr_html_formatter = ref F.std_formatter @@ -273,7 +223,7 @@ end = struct () ) ; F.fprintf fmt "@\n" in - LineReader.iter linereader filename ~f:print_one_line ; + LineReader.iteri linereader filename ~f:print_one_line ; F.fprintf fmt "@\n" ; Errlog.pp_html filename [fname_encoding] fmt global_err_log ; Io_infer.Html.close (fd, fmt) diff --git a/infer/src/backend/printer.mli b/infer/src/backend/printer.mli index 7f4e3eb55..1bfd8a610 100644 --- a/infer/src/backend/printer.mli +++ b/infer/src/backend/printer.mli @@ -10,18 +10,6 @@ open! IStd (** Printers for the analysis results *) -(** Module to read specific lines from files. The data from any file will stay in memory until the - handle is collected by the gc *) -module LineReader : sig - type t - - val create : unit -> t - (** create a line reader *) - - val from_loc : t -> Location.t -> string option - (** get the line from a location looking for the copy of the file in the results dir *) -end - val curr_html_formatter : Format.formatter ref (** Current html formatter *) diff --git a/infer/src/base/LineReader.ml b/infer/src/base/LineReader.ml new file mode 100644 index 000000000..a7d4e6b44 --- /dev/null +++ b/infer/src/base/LineReader.ml @@ -0,0 +1,55 @@ +(* + * Copyright (c) 2009-2013, Monoidics ltd. + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd +module Hashtbl = Caml.Hashtbl + +(** Map a file name to an array of string, one for each line in the file. *) +type t = (SourceFile.t, string array) Hashtbl.t + +let create () = Hashtbl.create 1 + +let read_file fname = + let cin = In_channel.create fname in + let lines = ref [] in + try + while true do + let line_raw = In_channel.input_line_exn cin in + let line = + let len = String.length line_raw in + if len > 0 && Char.equal line_raw.[len - 1] '\r' then + String.sub line_raw ~pos:0 ~len:(len - 1) + else line_raw + in + lines := line :: !lines + done ; + assert false (* execution never reaches here *) + with End_of_file -> In_channel.close cin ; Array.of_list_rev !lines + + +let file_data (hash : t) fname = + try Some (Hashtbl.find hash fname) + with Caml.Not_found -> ( + try + let lines_arr = read_file (SourceFile.to_abs_path fname) in + Hashtbl.add hash fname lines_arr ; Some lines_arr + with exn when SymOp.exn_not_failure exn -> None ) + + +let from_file_linenum hash fname linenum = + match file_data hash fname with + | Some lines_arr when linenum > 0 && linenum <= Array.length lines_arr -> + Some lines_arr.(linenum - 1) + | _ -> + None + + +let from_loc hash loc = from_file_linenum hash loc.Location.file loc.Location.line + +let iteri hash fname ~f = + file_data hash fname |> Option.iter ~f:(Array.iteri ~f:(fun linenum line -> f (linenum + 1) line)) diff --git a/infer/src/base/LineReader.mli b/infer/src/base/LineReader.mli new file mode 100644 index 000000000..d0b011ee1 --- /dev/null +++ b/infer/src/base/LineReader.mli @@ -0,0 +1,22 @@ +(* + * Copyright (c) 2009-2013, Monoidics ltd. + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd + +(** Module to read specific lines from files. The data from any file will stay in memory until the + handle is collected by the gc *) + +type t + +val create : unit -> t + +val from_loc : t -> Location.t -> string option +(** get the line from a location looking for the copy of the file in the results dir *) + +val iteri : t -> SourceFile.t -> f:(int -> string -> unit) -> unit +(** iterate on the lines of the file, with line numbers *) diff --git a/infer/src/integration/JsonReports.ml b/infer/src/integration/JsonReports.ml index e1772a90e..97e8926f1 100644 --- a/infer/src/integration/JsonReports.ml +++ b/infer/src/integration/JsonReports.ml @@ -307,7 +307,7 @@ let process_summary ~costs_outf summary issues_acc = let process_all_summaries_and_issues ~issues_outf ~costs_outf = - let linereader = Printer.LineReader.create () in + let linereader = LineReader.create () in let filters = Inferconfig.create_filters () in let all_issues = ref [] in SpecsFiles.iter_from_config ~f:(fun summary -> diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 2b1ce8a18..c1aa1b909 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -39,11 +39,11 @@ let get_start_location_heuristics = match line.[next_char_idx] with ' ' | '<' | '(' -> true | _ -> false else false ) in - let line_reader = lazy (Printer.LineReader.create ()) in + let line_reader = lazy (LineReader.create ()) in let rec find_proc_loc_backward name ~lines_to_find loc = if lines_to_find <= 0 || loc.Location.line <= 0 then None else - match Printer.LineReader.from_loc (Lazy.force_val line_reader) loc with + match LineReader.from_loc (Lazy.force_val line_reader) loc with | None -> None | Some line when is_proc_line line ~name -> diff --git a/infer/src/nullsafe/eradicate.ml b/infer/src/nullsafe/eradicate.ml index 8b135efab..ae69b455c 100644 --- a/infer/src/nullsafe/eradicate.ml +++ b/infer/src/nullsafe/eradicate.ml @@ -210,7 +210,7 @@ let analyze checks ({IntraproceduralAnalysis.proc_desc; tenv; _} as analysis_dat L.debug Analysis Medium "Signature: %a@\n" (AnnotatedSignature.pp proc_name) annotated_signature ; let loc = Procdesc.get_loc proc_desc in - let linereader = Printer.LineReader.create () in + let linereader = LineReader.create () in (* Initializing TypeErr signleton. *) TypeErr.reset () ; (* The main method - during this the actual analysis will happen and TypeErr will be populated with diff --git a/infer/src/nullsafe/eradicateChecks.ml b/infer/src/nullsafe/eradicateChecks.ml index 60782b467..6d4a414e4 100644 --- a/infer/src/nullsafe/eradicateChecks.ml +++ b/infer/src/nullsafe/eradicateChecks.ml @@ -79,7 +79,7 @@ let check_condition_for_redundancy in let from_try_with_resources () : bool = (* heuristic to check if the condition is the translation of try-with-resources *) - match Printer.LineReader.from_loc linereader loc with + match LineReader.from_loc linereader loc with | Some line -> (not (String.is_substring ~substring:"==" line || String.is_substring ~substring:"!=" line)) && String.is_substring ~substring:"}" line diff --git a/infer/src/nullsafe/typeCheck.mli b/infer/src/nullsafe/typeCheck.mli index a4e865206..44ff8ba97 100644 --- a/infer/src/nullsafe/typeCheck.mli +++ b/infer/src/nullsafe/typeCheck.mli @@ -34,6 +34,6 @@ val typecheck_node : -> AnnotatedSignature.t -> TypeState.t -> Procdesc.Node.t - -> Printer.LineReader.t + -> LineReader.t -> typecheck_result (** Main entry point. Typecheck the CFG node given input typestate, and report issues, if found *)