diff --git a/.gitignore b/.gitignore index c9d78ff5a..77ac521e4 100644 --- a/.gitignore +++ b/.gitignore @@ -137,7 +137,6 @@ buck-out/ /infer/src/clang/clang_ast_v.ml /infer/src/clang/clang_ast_v.mli /infer/src/clang/clang_ast_visit.ml -/infer/src/clang/clang_ast_main.ml /infer/src/clang/clang_ast_types.ml /infer/annotations/annot_classes/ diff --git a/infer/src/Makefile b/infer/src/Makefile index 0a56bbdeb..f75780002 100644 --- a/infer/src/Makefile +++ b/infer/src/Makefile @@ -109,8 +109,7 @@ CLANG_ATDGEN_STUBS = $(addprefix $(CLANG_ATDGEN_STUB_BASE), $(CLANG_ATDGEN_SUFFI FCP_CLANG_AST_PROJ = $(addprefix $(FCP_CLANG_OCAML_BUILD_DIR)/, \ clang_ast_proj.ml clang_ast_proj.mli) -FCP_CLANG_AST_MAIN = $(addprefix $(FCP_CLANG_OCAML_DIR)/, \ - clang_ast_visit.ml clang_ast_main.ml clang_ast_types.ml) +FCP_CLANG_AST_MAIN = $(addprefix $(FCP_CLANG_OCAML_DIR)/, clang_ast_visit.ml clang_ast_types.ml) FCP_FILES_TO_MIRROR = $(FCP_CLANG_AST_PROJ) $(FCP_CLANG_AST_MAIN) INFER_CLANG_FCP_MIRRORED_FILES = $(addprefix $(CLANG_SOURCES)/, $(notdir $(FCP_FILES_TO_MIRROR))) diff --git a/infer/src/clang/Capture.re b/infer/src/clang/Capture.re index f722623d2..2861e2518 100644 --- a/infer/src/clang/Capture.re +++ b/infer/src/clang/Capture.re @@ -53,7 +53,6 @@ let init_global_state_for_capture_and_linters source_file => { register_perf_stats_report source_file; Config.curr_language := Config.Clang; DB.Results_dir.init source_file; - Clang_ast_main.reset_cache (); CFrontend_config.reset_global_state () }; @@ -91,12 +90,7 @@ let run_clang_frontend ast_source => { | `Pipe _ => Format.fprintf fmt "stdin of %a" SourceFile.pp trans_unit_ctx.CFrontend_config.source_file }; - let (decl_index, stmt_index, type_index, ivar_to_property_index) = - Clang_ast_main.index_node_pointers ast_decl; - CFrontend_config.pointer_decl_index := decl_index; - CFrontend_config.pointer_stmt_index := stmt_index; - CFrontend_config.pointer_type_index := type_index; - CFrontend_config.ivar_to_property_index := ivar_to_property_index; + ClangPointers.populate_all_tables ast_decl; Logging.out "Clang frontend action is %s@\n" Config.clang_frontend_action_string; Logging.out "Start %s of AST from %a@\n" Config.clang_frontend_action_string pp_ast_filename ast_source; diff --git a/infer/src/clang/ClangPointers.ml b/infer/src/clang/ClangPointers.ml new file mode 100644 index 000000000..5940920dc --- /dev/null +++ b/infer/src/clang/ClangPointers.ml @@ -0,0 +1,112 @@ +(* + * Copyright (c) 2015 - 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! IStd + +type t = Clang_ast_t.pointer + +module Map = Map.Make(Int) + +let ivar_to_property_table = Int.Table.create ~size:256 () +let pointer_decl_table = Int.Table.create ~size:256 () +let pointer_stmt_table = Int.Table.create ~size:256 () +let pointer_type_table = Int.Table.create ~size:256 () + +let empty_v = Clang_ast_visit.empty_visitor +(* This function is not thread-safe *) +let visit_ast + ?(visit_decl=empty_v) ?(visit_stmt=empty_v) ?(visit_type=empty_v) ?(visit_src_loc=empty_v) + top_decl = + Clang_ast_visit.decl_visitor := visit_decl; + Clang_ast_visit.stmt_visitor := visit_stmt; + Clang_ast_visit.type_visitor := visit_type; + Clang_ast_visit.source_location_visitor := visit_src_loc; + match Clang_ast_v.validate_decl [] top_decl (* visit *) with + | None -> + () + | Some error -> + failwithf "ERROR: visiting the clang AST failed with error %s" + (Ag_util.Validation.string_of_error error) + +let get_ptr_from_node node = + match node with + | `DeclNode decl -> + let decl_info = Clang_ast_proj.get_decl_tuple decl in + decl_info.Clang_ast_t.di_pointer + | `StmtNode stmt -> + let stmt_info,_ = Clang_ast_proj.get_stmt_tuple stmt in + stmt_info.Clang_ast_t.si_pointer + | `TypeNode c_type -> + let type_info = Clang_ast_proj.get_type_tuple c_type in + type_info.Clang_ast_t.ti_pointer + +let get_val_from_node node = + match node with + | `DeclNode decl -> decl + | `StmtNode stmt -> stmt + | `TypeNode c_type -> c_type + +let add_node_to_cache node cache = + let key = get_ptr_from_node node in + let data = get_val_from_node node in + Int.Table.set cache ~key ~data + +let process_decl _ decl = + add_node_to_cache (`DeclNode decl) pointer_decl_table; + match decl with + | Clang_ast_t.ObjCPropertyDecl (_, _, {opdi_ivar_decl=Some decl_ref}) -> + let ivar_pointer = decl_ref.Clang_ast_t.dr_decl_pointer in + Int.Table.set ivar_to_property_table ~key:ivar_pointer ~data:decl + | _ -> () + +let add_stmt_to_cache _ stmt = + add_node_to_cache (`StmtNode stmt) pointer_stmt_table + +let add_type_to_cache _ c_type = + add_node_to_cache (`TypeNode c_type) pointer_type_table + +let previous_sloc = { Clang_ast_t.sl_file = None; sl_line = None; sl_column = None } + +let get_sloc current previous = + match current with + | None -> previous + | Some _ -> current + +let mutate_sloc sloc file line column = + let open Clang_ast_t in + sloc.sl_file <- file; + sloc.sl_line <- line; + sloc.sl_column <- column + +let reset_sloc sloc = mutate_sloc sloc None None None + +let complete_source_location _ source_loc = + let open Clang_ast_t in + let file = get_sloc source_loc.sl_file previous_sloc.sl_file in + let line = get_sloc source_loc.sl_line previous_sloc.sl_line in + let column = get_sloc source_loc.sl_column previous_sloc.sl_column in + mutate_sloc source_loc file line column; + mutate_sloc previous_sloc file line column + +let reset_cache () = + Int.Table.clear pointer_decl_table; + Int.Table.clear pointer_stmt_table; + Int.Table.clear pointer_type_table; + Int.Table.clear ivar_to_property_table; + reset_sloc previous_sloc + +(* This function is not thread-safe *) +let populate_all_tables top_decl = + reset_cache (); + (* populate caches *) + visit_ast + ~visit_decl:process_decl + ~visit_stmt:add_stmt_to_cache + ~visit_type:add_type_to_cache + ~visit_src_loc:complete_source_location top_decl diff --git a/infer/src/clang/ClangPointers.mli b/infer/src/clang/ClangPointers.mli new file mode 100644 index 000000000..70c261c4f --- /dev/null +++ b/infer/src/clang/ClangPointers.mli @@ -0,0 +1,30 @@ +(* + * Copyright (c) 2017 - 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! IStd + +(** pointers produced by the AST exporter to represent sharing in the AST *) +type t = Clang_ast_t.pointer + +module Map : module type of Map.Make(Int) + +(** maps ivar decl pointer to its decl record *) +val ivar_to_property_table : Clang_ast_t.decl Int.Table.t + +(** maps decl pointer to its decl record *) +val pointer_decl_table : Clang_ast_t.decl Int.Table.t + +(** maps stmt pointer to its stmt record *) +val pointer_stmt_table : Clang_ast_t.stmt Int.Table.t + +(** map pointer to its type *) +val pointer_type_table : Clang_ast_t.c_type Int.Table.t + +(** discover what pointers should point to in the tables above; should be run once for the current + toplevel decl *) +val populate_all_tables : Clang_ast_t.decl -> unit diff --git a/infer/src/clang/cAst_utils.ml b/infer/src/clang/cAst_utils.ml index 0ca8ae9ec..2844155d7 100644 --- a/infer/src/clang/cAst_utils.ml +++ b/infer/src/clang/cAst_utils.ml @@ -61,9 +61,9 @@ let type_from_unary_expr_or_type_trait_expr_info info = | None -> None let get_decl decl_ptr = - try - Some (Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.pointer_decl_index) - with Not_found -> Logging.out "decl with pointer %d not found\n" decl_ptr; None + let decl = Int.Table.find ClangPointers.pointer_decl_table decl_ptr in + if Option.is_none decl then Logging.out "decl with pointer %d not found\n" decl_ptr; + decl let get_decl_opt decl_ptr_opt = match decl_ptr_opt with @@ -71,9 +71,9 @@ let get_decl_opt decl_ptr_opt = | None -> None let get_stmt stmt_ptr = - try - Some (Clang_ast_main.PointerMap.find stmt_ptr !CFrontend_config.pointer_stmt_index) - with Not_found -> Logging.out "stmt with pointer %d not found\n" stmt_ptr; None + let stmt = Int.Table.find ClangPointers.pointer_stmt_table stmt_ptr in + if Option.is_none stmt then Logging.out "stmt with pointer %d not found\n" stmt_ptr; + stmt let get_stmt_opt stmt_ptr_opt = match stmt_ptr_opt with @@ -86,41 +86,36 @@ let get_decl_opt_with_decl_ref decl_ref_opt = | None -> None let get_property_of_ivar decl_ptr = - try - Some (Clang_ast_main.PointerMap.find decl_ptr !CFrontend_config.ivar_to_property_index) - with Not_found -> Logging.out "property with pointer %d not found\n" decl_ptr; None + let decl = Int.Table.find ClangPointers.ivar_to_property_table decl_ptr in + if Option.is_none decl then Logging.out "property with pointer %d not found\n" decl_ptr; + decl let update_sil_types_map type_ptr sil_type = CFrontend_config.sil_types_map := Clang_ast_extend.TypePointerMap.add type_ptr sil_type !CFrontend_config.sil_types_map let update_enum_map enum_constant_pointer sil_exp = - let open Clang_ast_main in let (predecessor_pointer_opt, _) = - try PointerMap.find enum_constant_pointer !CFrontend_config.enum_map - with Not_found -> assert false in + ClangPointers.Map.find_exn !CFrontend_config.enum_map enum_constant_pointer in let enum_map_value = (predecessor_pointer_opt, Some sil_exp) in CFrontend_config.enum_map := - PointerMap.add enum_constant_pointer enum_map_value !CFrontend_config.enum_map + ClangPointers.Map.add !CFrontend_config.enum_map ~key:enum_constant_pointer ~data:enum_map_value let add_enum_constant enum_constant_pointer predecessor_pointer_opt = let enum_map_value = (predecessor_pointer_opt, None) in CFrontend_config.enum_map := - Clang_ast_main.PointerMap.add enum_constant_pointer enum_map_value !CFrontend_config.enum_map + ClangPointers.Map.add !CFrontend_config.enum_map ~key:enum_constant_pointer ~data:enum_map_value let get_enum_constant_exp enum_constant_pointer = - Clang_ast_main.PointerMap.find enum_constant_pointer !CFrontend_config.enum_map + ClangPointers.Map.find_exn !CFrontend_config.enum_map enum_constant_pointer let get_type type_ptr = (* There is chance for success only if type_ptr is in fact clang pointer *) match type_ptr with | Clang_ast_types.TypePtr.Ptr raw_ptr -> - (try - Some (Clang_ast_main.PointerMap.find raw_ptr !CFrontend_config.pointer_type_index) - with Not_found -> - Logging.out "type with pointer %d not found\n" raw_ptr; - None - ) + let typ = Int.Table.find ClangPointers.pointer_type_table raw_ptr in + if Option.is_none typ then Logging.out "type with pointer %d not found\n" raw_ptr; + typ | _ -> (* otherwise, function fails *) let type_str = Clang_ast_extend.type_ptr_to_string type_ptr in diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 9c41f43ed..55fd98157 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -93,21 +93,13 @@ let modeled_function_attributes = [replace_with_deref_first_arg_attr] (** Global state *) -let enum_map = ref Clang_ast_main.PointerMap.empty +let enum_map = ref ClangPointers.Map.empty let global_translation_unit_decls : Clang_ast_t.decl list ref = ref [] -let ivar_to_property_index = ref Clang_ast_main.PointerMap.empty let log_out = ref Format.std_formatter -let pointer_decl_index = ref Clang_ast_main.PointerMap.empty -let pointer_stmt_index = ref Clang_ast_main.PointerMap.empty -let pointer_type_index = ref Clang_ast_main.PointerMap.empty let sil_types_map = ref Clang_ast_extend.TypePointerMap.empty let reset_global_state () = - enum_map := Clang_ast_main.PointerMap.empty; + enum_map := ClangPointers.Map.empty; global_translation_unit_decls := []; - ivar_to_property_index := Clang_ast_main.PointerMap.empty; log_out := Format.std_formatter; - pointer_decl_index := Clang_ast_main.PointerMap.empty; - pointer_stmt_index := Clang_ast_main.PointerMap.empty; - pointer_type_index := Clang_ast_main.PointerMap.empty; sil_types_map := Clang_ast_extend.TypePointerMap.empty; diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index 3985b7c43..5882a4a82 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -93,15 +93,9 @@ val modeled_function_attributes : string list (** Global state *) (** Map from enum constants pointers to their predecesor and their sil value *) -val enum_map : (Clang_ast_t.pointer option * Exp.t option) Clang_ast_main.PointerMap.t ref +val enum_map : (Clang_ast_t.pointer option * Exp.t option) ClangPointers.Map.t ref val global_translation_unit_decls : Clang_ast_t.decl list ref -val ivar_to_property_index : Clang_ast_t.decl Clang_ast_main.PointerMap.t ref val log_out : Format.formatter ref -val pointer_decl_index : Clang_ast_t.decl Clang_ast_main.PointerMap.t ref -val pointer_stmt_index : Clang_ast_t.stmt Clang_ast_main.PointerMap.t ref - -(** Map from clang pointers to types produced by ast exporter. Populated once on startup *) -val pointer_type_index : Clang_ast_t.c_type Clang_ast_main.PointerMap.t ref (** Map from type pointers (clang pointers and types created later by frontend) to sil types Populated during frontend execution when new type is found *) diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 71cfef936..51b6fa9ca 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -1677,8 +1677,8 @@ struct { empty_res_trans with root_nodes = trans_state.succ_nodes } and init_dynamic_array trans_state array_exp_typ array_stmt_info dynlength_stmt_pointer = - let dynlength_stmt = Clang_ast_main.PointerMap.find dynlength_stmt_pointer - !CFrontend_config.pointer_stmt_index in + let dynlength_stmt = Int.Table.find_exn ClangPointers.pointer_stmt_table + dynlength_stmt_pointer in let dynlength_stmt_info, _ = Clang_ast_proj.get_stmt_tuple dynlength_stmt in let trans_state_pri = PriorityNode.try_claim_priority_node trans_state array_stmt_info in let dynlength_trans_result = instruction trans_state_pri dynlength_stmt in