From d7a0e706df491af2b2955e4cfef4cff8630752f5 Mon Sep 17 00:00:00 2001 From: Andrzej Kotulski Date: Thu, 20 Oct 2016 08:18:40 -0700 Subject: [PATCH] [clang] Create separate module for compilation database Summary: Move compilation database into separate module which loads said database from json file. It will allow to load database from json file without calling buck. Reviewed By: dulmarod Differential Revision: D4049255 fbshipit-source-id: b2fa29f --- infer/src/clang/CompilationDatabase.ml | 54 +++++++++++++++++ infer/src/clang/CompilationDatabase.mli | 28 +++++++++ .../integration/BuckCompilationDatabase.ml | 60 +++---------------- 3 files changed, 91 insertions(+), 51 deletions(-) create mode 100644 infer/src/clang/CompilationDatabase.ml create mode 100644 infer/src/clang/CompilationDatabase.mli diff --git a/infer/src/clang/CompilationDatabase.ml b/infer/src/clang/CompilationDatabase.ml new file mode 100644 index 000000000..2dcde2f51 --- /dev/null +++ b/infer/src/clang/CompilationDatabase.ml @@ -0,0 +1,54 @@ +(* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + *) + +open! Utils + +type compilation_data = { + dir : string; + command : string; + args : string list; +} + +type t = compilation_data StringMap.t ref +let empty () = ref StringMap.empty + +let get_size database = StringMap.cardinal !database + +let iter database f = StringMap.iter f !database + +let find database key = StringMap.find key !database + +(** Parse the compilation database json file into the compilationDatabase + map. The json file consists of an array of json objects that contain the file + to be compiled, the directory to be compiled in, and the compilation command as a list + and as a string. We pack this information into the compilationDatabase map, and remove the + clang invocation part, because we will use a clang wrapper. *) +let decode_json_file (database : t) should_add_file json_path = + let json = Yojson.Basic.from_file json_path in + let parse_argument compilation_argument = + match compilation_argument with + | `String arg -> arg + | _ -> failwith ("Json file doesn't have the expected format") in + let rec parse_json json = + match json with + | `List arguments -> + IList.iter parse_json arguments + | `Assoc [ ("directory", `String dir); + ("file", `String file_path); + ("arguments", `List compilation_arguments); + ("command", `String _) ] -> + (match IList.map parse_argument compilation_arguments with + | [] -> failwith ("Command cannot be empty") + | command :: args when should_add_file file_path -> + let compilation_data = { dir; command; args;} in + database := StringMap.add file_path compilation_data !database + | _ -> ()) + | _ -> + failwith ("Json file doesn't have the expected format") in + parse_json json diff --git a/infer/src/clang/CompilationDatabase.mli b/infer/src/clang/CompilationDatabase.mli new file mode 100644 index 000000000..ebd24d187 --- /dev/null +++ b/infer/src/clang/CompilationDatabase.mli @@ -0,0 +1,28 @@ +(* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + *) + +open! Utils + +type t + +type compilation_data = { + dir : string; + command : string; + args : string list; +} + +val empty : unit -> t + +val get_size : t -> int + +val iter : t -> (string -> compilation_data -> unit) -> unit + +val find : t -> string -> compilation_data + +val decode_json_file : t -> (string -> bool) -> string -> unit diff --git a/infer/src/integration/BuckCompilationDatabase.ml b/infer/src/integration/BuckCompilationDatabase.ml index b0b2b3479..38598ede5 100644 --- a/infer/src/integration/BuckCompilationDatabase.ml +++ b/infer/src/integration/BuckCompilationDatabase.ml @@ -8,13 +8,6 @@ *) open! Utils -module YBU = Yojson.Basic.Util - -type compilation_data = { - dir : string; - command : string; - args : string list; -} let capture_text = if Config.analyzer = Some Config.Linters then "linting" @@ -50,45 +43,6 @@ let read_files_to_compile () = DB.SourceFileSet.add file changed_files) changed_files lines -(** Add file to compilation database, only if it is in changed_files. *) -let add_file_to_compilation_database file_path cmd_options changed_files compilation_database = - let add_file = - match Config.changed_files_index with - | Some _ -> DB.SourceFileSet.mem (DB.source_file_from_string file_path) changed_files - | None -> true in - if add_file then - compilation_database := StringMap.add file_path cmd_options !compilation_database - - -(** Parse the compilation database json file into the compilationDatabase - map. The json file consists of an array of json objects that contain the file - to be compiled, the directory to be compiled in, and the compilation command as a list - and as a string. We pack this information into the compilationDatabase map, and remove the - clang invocation part, because we will use a clang wrapper. *) -let decode_compilation_database changed_files compilation_database _ path = - let json = Yojson.Basic.from_file path in - let parse_argument compilation_argument = - match compilation_argument with - | `String arg -> arg - | _ -> failwith ("Json file doesn't have the expected format") in - let rec parse_json json = - match json with - | `List arguments -> - IList.iter parse_json arguments - | `Assoc [ ("directory", `String dir); - ("file", `String file_path); - ("arguments", `List compilation_arguments); - ("command", `String _) ] -> - (match IList.map parse_argument compilation_arguments with - | [] -> failwith ("Command cannot be empty") - | command :: args -> - let compilation_data = { dir; command; args;} in - add_file_to_compilation_database file_path compilation_data changed_files - compilation_database) - | _ -> - failwith ("Json file doesn't have the expected format") in - parse_json json - (** The buck targets are assumed to start with //, aliases are not supported. *) let check_args_for_targets args = if not (IList.exists (Utils.string_is_prefix "//") args) then @@ -113,7 +67,7 @@ let create_files_stack compilation_database = let stack = Stack.create () in let add_to_stack file _ = Stack.push file stack in - StringMap.iter add_to_stack !compilation_database; + CompilationDatabase.iter compilation_database add_to_stack; stack let swap_command cmd = @@ -143,7 +97,7 @@ let replace_clang_arg arg = let run_compilation_file compilation_database file = try - let compilation_data = StringMap.find file !compilation_database in + let compilation_data = CompilationDatabase.find compilation_database file in Unix.chdir compilation_data.dir; let wrapper_cmd = swap_command compilation_data.command in let replaced_args = IList.map replace_clang_arg compilation_data.args |> IList.flatten in @@ -156,7 +110,7 @@ let run_compilation_file compilation_database file = Process.print_error_and_exit "Failed to find compilation data for %s \n%!" file let run_compilation_database compilation_database = - let number_of_files = StringMap.cardinal !compilation_database in + let number_of_files = CompilationDatabase.get_size compilation_database in Logging.out "Starting %s %d files \n%!" capture_text number_of_files; Logging.stdout "Starting %s %d files \n%!" capture_text number_of_files; let jobsStack = create_files_stack compilation_database in @@ -188,9 +142,13 @@ let get_compilation_database changed_files = (fun target file -> StringMap.add target file compilation_database_files) in (* Map from targets to json output *) let compilation_database_files = IList.fold_left scan_output StringMap.empty lines in - let compilation_database = ref StringMap.empty in + let compilation_database = CompilationDatabase.empty () in + let should_add_file file_path = + match Config.changed_files_index with + | Some _ -> DB.SourceFileSet.mem (DB.source_file_from_string file_path) changed_files + | None -> true in StringMap.iter - (decode_compilation_database changed_files compilation_database) + (fun _ file -> CompilationDatabase.decode_json_file compilation_database should_add_file file) compilation_database_files; compilation_database with Unix.Unix_error (err, _, _) ->