Update fcp to get automatic location visitor

Summary:
public
Use generic location visitor from facebook-clang-plugins
Therefore, there is no need to write our custom visitor which is hard to maintain
This introduces some level of magic, but makes it easier to maintain the code.

Reviewed By: jvillard

Differential Revision: D2734282

fb-gh-sync-id: ed9711a
master
Andrzej Kotulski 9 years ago committed by facebook-github-bot-1
parent eeb7c33230
commit 6d7521809b

@ -1 +1 @@
Subproject commit 545b4f6e27473523ad624e9a6305d7fa234946d4
Subproject commit 07c2aabb21fb201ac01b261095b665a53a00a9a1

@ -1,351 +0,0 @@
(*
* 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.
*)
(** Module to preprocess location information in the AST.
The original location information is incremental, each location is a delta
w.r.t. the previous one. This module processes the AST and makes locations explicit. *)
open Utils
module L = Logging
module F = Format
(** Get the sub-declarations of the current declaration. *)
let decl_get_sub_decls decl =
let open Clang_ast_t in
match decl with
| CXXRecordDecl (_, _, _, _, decl_list, _, _, _)
| ClassTemplateSpecializationDecl (_, _, _, _, decl_list, _, _, _)
| RecordDecl (_, _, _, _, decl_list, _, _)
| ObjCInterfaceDecl (_, _, decl_list, _, _)
| ObjCProtocolDecl (_, _, decl_list, _, _)
| ObjCCategoryDecl (_, _, decl_list, _, _)
| ObjCCategoryImplDecl (_, _, decl_list, _, _)
| ObjCImplementationDecl (_, _, decl_list, _, _)
| EnumDecl (_, _, _, _, decl_list, _, _)
| LinkageSpecDecl (_, decl_list, _)
| NamespaceDecl (_, _, decl_list, _, _) ->
decl_list
| ClassTemplateDecl (_, _, template_decl_info)
| FunctionTemplateDecl (_, _, template_decl_info) ->
template_decl_info.tdi_specializations
| _ ->
[]
(** Set the sub-declarations of the current declaration. *)
let decl_set_sub_decls decl decl_list' =
let open Clang_ast_t in
match decl with
| CXXRecordDecl (decl_info, name, opt_type, type_ptr, decl_list, decl_context_info, record_decl_info, cxx_record_info) ->
CXXRecordDecl (decl_info, name, opt_type, type_ptr, decl_list', decl_context_info, record_decl_info, cxx_record_info)
| ClassTemplateSpecializationDecl (decl_info, name, opt_type, type_ptr, decl_list, decl_context_info, record_decl_info, cxx_record_info) ->
ClassTemplateSpecializationDecl (decl_info, name, opt_type, type_ptr, decl_list', decl_context_info, record_decl_info, cxx_record_info)
| RecordDecl (decl_info, name, opt_type, type_ptr, decl_list, decl_context_info, record_decl_info) ->
RecordDecl (decl_info, name, opt_type, type_ptr, decl_list', decl_context_info, record_decl_info)
| ObjCInterfaceDecl (decl_info, name, decl_list, decl_context_info, obj_c_interface_decl_info) ->
ObjCInterfaceDecl (decl_info, name, decl_list', decl_context_info, obj_c_interface_decl_info)
| ObjCProtocolDecl (decl_info, name, decl_list, decl_context_info, obj_c_protocol_decl_info) ->
ObjCProtocolDecl (decl_info, name, decl_list', decl_context_info, obj_c_protocol_decl_info)
| ObjCCategoryDecl (decl_info, name, decl_list, decl_context_info, category_decl_info) ->
ObjCCategoryDecl (decl_info, name, decl_list', decl_context_info, category_decl_info)
| ObjCCategoryImplDecl (decl_info, name, decl_list, decl_context_info, category_impl_info) ->
ObjCCategoryImplDecl (decl_info, name, decl_list', decl_context_info, category_impl_info)
| ObjCImplementationDecl (decl_info, class_name, decl_list, decl_context_info, idi) ->
ObjCImplementationDecl (decl_info, class_name, decl_list', decl_context_info, idi)
| EnumDecl (decl_info, name, opt_type, type_ptr, decl_list, decl_context_info, enum_decl_info) ->
EnumDecl (decl_info, name, opt_type, type_ptr, decl_list', decl_context_info, enum_decl_info)
| LinkageSpecDecl (decl_info, decl_list, decl_context_info) ->
LinkageSpecDecl (decl_info, decl_list', decl_context_info)
| NamespaceDecl (decl_info, name, decl_list, decl_context_info, namespace_decl_info) ->
NamespaceDecl (decl_info, name, decl_list', decl_context_info, namespace_decl_info)
| ClassTemplateDecl (decl_info, name, template_decl_info) ->
let template_decl_info' = { tdi_specializations = decl_list' } in
ClassTemplateDecl (decl_info, name, template_decl_info')
| FunctionTemplateDecl (decl_info, name, template_decl_info) ->
let template_decl_info' = { tdi_specializations = decl_list' } in
FunctionTemplateDecl (decl_info, name, template_decl_info')
| _ ->
decl
(** Pretty print a source location. *)
let pp_source_loc fmt source_loc =
let file = match source_loc.Clang_ast_t.sl_file with
| Some file -> file
| None -> "None" in
let line = match source_loc.Clang_ast_t.sl_line with
| Some n -> string_of_int n
| None -> "None" in
let column = match source_loc.Clang_ast_t.sl_column with
| Some n -> string_of_int n
| None -> "None" in
if file = "None" && line = "None" && column = "None"
then F.fprintf fmt "_"
else F.fprintf fmt "%s:%s:%s" file line column
(** Pretty print a source range. *)
let pp_source_range fmt (sloc1, sloc2) =
F.fprintf fmt "<%a, %a>" pp_source_loc sloc1 pp_source_loc sloc2
(** Pretty print an AST. *)
let pp_ast_decl fmt ast_decl =
let rec dump_stmt prefix stmt =
let prefix1 = prefix ^ " " in
let stmt_str = Clang_ast_proj.get_stmt_kind_string stmt in
let stmt_info, stmt_list = Clang_ast_proj.get_stmt_tuple stmt in
let decl_list = match stmt with
| Clang_ast_t.DeclStmt (_, _, decl_list) -> decl_list
| Clang_ast_t.BlockExpr (_, _, _, decl) -> [decl]
| _ -> [] in
F.fprintf fmt "%s%s %a@\n"
prefix
stmt_str
pp_source_range stmt_info.Clang_ast_t.si_source_range;
IList.iter (dump_stmt prefix1) stmt_list;
IList.iter (dump_decl prefix1) decl_list
and dump_decl prefix decl =
let prefix1 = prefix ^ " " in
let open Clang_ast_t in
match decl with
| BlockDecl (decl_info, block_decl_info) ->
F.fprintf fmt "%sBlockDecl %a@\n"
prefix
pp_source_range decl_info.di_source_range;
Option.may (dump_stmt prefix1) block_decl_info.bdi_body
| FunctionDecl (decl_info, name, tp, fdecl_info) ->
F.fprintf fmt "%sFunctionDecl %s %a@\n"
prefix
name.Clang_ast_t.ni_name
pp_source_range decl_info.di_source_range;
IList.iter (dump_decl prefix1) fdecl_info.fdi_decls_in_prototype_scope;
IList.iter (dump_decl prefix1) fdecl_info.fdi_parameters;
Option.may (dump_stmt prefix1) fdecl_info.fdi_body
| ObjCMethodDecl (decl_info, name, obj_c_method_decl_info) ->
F.fprintf fmt "%sObjCMethodDecl %s %a@\n"
prefix
name.Clang_ast_t.ni_name
pp_source_range decl_info.di_source_range;
Option.may (dump_stmt prefix1) obj_c_method_decl_info.omdi_body
| VarDecl (decl_info, name, type_ptr, var_decl_info) ->
F.fprintf fmt "%sVarDecl %a@\n"
prefix
pp_source_range decl_info.di_source_range;
Option.may (dump_stmt prefix1) var_decl_info.vdi_init_expr
| _ ->
let decl_kind_str = Clang_ast_proj.get_decl_kind_string decl in
let decl_info = Clang_ast_proj.get_decl_tuple decl in
let decl_list = decl_get_sub_decls decl in
F.fprintf fmt "%s%s %a@\n"
prefix
decl_kind_str
pp_source_range decl_info.di_source_range;
IList.iter (dump_decl prefix1) decl_list in
let decl_str = Clang_ast_proj.get_decl_kind_string ast_decl in
match ast_decl with
| Clang_ast_t.TranslationUnitDecl (_, decl_list, _, _) ->
F.fprintf fmt "%s (%d declarations)@\n" decl_str (IList.length decl_list);
IList.iter (dump_decl "") decl_list
| _ ->
assert false
(** Compose incremental location information and make locations explicit. *)
module LocComposer : sig
(** Status of the composer. *)
type status
(** Create a new composer with the initial status. *)
val create : unit -> status
(** Compose a new source_range to the current one. *)
val compose : status -> Clang_ast_t.source_range -> Clang_ast_t.source_range
(** Set the current file if specified in the source_range.
The composer will not descend into file included from the current one.
For locations in included files, it will return instead the last known
location of the current file. *)
val set_current_file : status -> Clang_ast_t.source_range -> unit
end = struct
type status =
{ mutable curr_file: string option;
mutable curr_source_range: Clang_ast_t.source_range;
mutable in_curr_file : bool }
let empty_sloc = { Clang_ast_t.sl_file = None; sl_line = None; sl_column = None }
let create () =
{ curr_file = None;
curr_source_range = (empty_sloc, empty_sloc);
in_curr_file = true; }
let set_current_file st (sloc1, sloc2) =
match sloc1.Clang_ast_t.sl_file, sloc2.Clang_ast_t.sl_file with
| _, Some fname
| Some fname, None ->
st.curr_file <- Some fname;
st.in_curr_file <- true
| _ ->
()
let sloc_is_current_file st sloc = match st.curr_file, sloc.Clang_ast_t.sl_file with
| Some curr_f, Some f ->
Some (f = curr_f)
| None, _ -> None
| _, None -> None
let update_sloc st old_sloc new_sloc =
match sloc_is_current_file st new_sloc with
| Some true ->
st.in_curr_file <- true;
new_sloc
| Some false ->
st.in_curr_file <- false;
old_sloc
| None ->
if st.in_curr_file
then
let update x_opt y_opt =
if y_opt <> None then y_opt else x_opt in
let open Clang_ast_t in
{ sl_file = update old_sloc.sl_file new_sloc.sl_file;
sl_line = update old_sloc.sl_line new_sloc.sl_line;
sl_column = update old_sloc.sl_column new_sloc.sl_column }
else
old_sloc
let update_status st (sloc1, sloc2) =
if sloc1 = empty_sloc && sloc2 = empty_sloc
then
()
else
let _, old_sloc2 = st.curr_source_range in
let new_sloc1 = update_sloc st old_sloc2 sloc1 in
let new_sloc2 = update_sloc st new_sloc1 sloc2 in
st.curr_source_range <- (new_sloc1, new_sloc2)
let compose st source_range =
update_status st source_range;
st.curr_source_range
end
let ctor_initializer_process_locs loc_composer ctor_init =
let range' = LocComposer.compose loc_composer ctor_init.Clang_ast_t.xci_source_range in
{ ctor_init with Clang_ast_t.xci_source_range = range'}
(** Apply a location composer to the locations in a statement. *)
let rec stmt_process_locs loc_composer stmt =
let update (stmt_info, stmt_list) =
let range' = LocComposer.compose loc_composer stmt_info.Clang_ast_t.si_source_range in
let stmt_info' =
{ stmt_info with
Clang_ast_t.si_source_range = range' } in
let stmt_list' = IList.map (stmt_process_locs loc_composer) stmt_list in
(stmt_info', stmt_list') in
let open Clang_ast_t in
match Clang_ast_proj.update_stmt_tuple update stmt with
| DeclStmt (stmt_info, stmt_list, decl_list) ->
let decl_list' = IList.map (decl_process_locs loc_composer) decl_list in
DeclStmt (stmt_info, stmt_list, decl_list')
| BlockExpr (stmt_info, stmt_list, expr_info, block_decl) ->
let block_decl' = decl_process_locs loc_composer block_decl in
BlockExpr (stmt_info, stmt_list, expr_info, block_decl')
| OpaqueValueExpr (stmt_info, stmt_list, expr_info, opaque_value_ei) ->
let source_expr = opaque_value_ei.ovei_source_expr in
let ovei_source_expr' = Option.map (stmt_process_locs loc_composer) source_expr in
let opaque_value_ei' = { ovei_source_expr = ovei_source_expr' } in
OpaqueValueExpr (stmt_info, stmt_list, expr_info, opaque_value_ei')
| stmt' ->
stmt'
(** Apply a location composer to the locations in a declaration. *)
and decl_process_locs loc_composer decl =
let decl' =
let update decl_info =
let range' = LocComposer.compose loc_composer decl_info.Clang_ast_t.di_source_range in
{ decl_info with
Clang_ast_t.di_source_range = range' } in
let decl_list = decl_get_sub_decls decl in
let decl1 = Clang_ast_proj.update_decl_tuple update decl in
let decl_list' = IList.map (decl_process_locs loc_composer) decl_list in
decl_set_sub_decls decl1 decl_list' in
let open Clang_ast_t in
let get_updated_fun_decl (decl_info', name, tp, fdecl_info) =
let fdi_decls_in_prototype_scope' =
IList.map (decl_process_locs loc_composer) fdecl_info.fdi_decls_in_prototype_scope in
let fdi_parameters' =
IList.map (decl_process_locs loc_composer) fdecl_info.fdi_parameters in
let body' = Option.map (stmt_process_locs loc_composer) fdecl_info.fdi_body in
let fdecl_info' =
{ fdecl_info with
fdi_body = body';
fdi_parameters = fdi_parameters';
fdi_decls_in_prototype_scope = fdi_decls_in_prototype_scope'; } in
(decl_info', name, tp, fdecl_info') in
let get_updated_method_decl (decl_info', name, tp, fdecl_info, method_info) =
let di', n', tp', fdi' = get_updated_fun_decl (decl_info', name, tp, fdecl_info) in
let ctor_init = method_info.xmdi_cxx_ctor_initializers in
let ctor_init' = IList.map (ctor_initializer_process_locs loc_composer) ctor_init in
let method_info' = { method_info with xmdi_cxx_ctor_initializers = ctor_init'} in
(di', n', tp', fdi', method_info') in
match decl' with
| BlockDecl (decl_info', block_decl_info) ->
let parameters' = IList.map (decl_process_locs loc_composer) block_decl_info.bdi_parameters in
let body' =
Option.map (stmt_process_locs loc_composer) block_decl_info.bdi_body in
let block_decl_info' =
{ block_decl_info with
bdi_body = body';
bdi_parameters = parameters'; } in
BlockDecl (decl_info', block_decl_info')
| FunctionDecl fun_info -> FunctionDecl (get_updated_fun_decl fun_info)
| CXXMethodDecl meth_info -> CXXMethodDecl (get_updated_method_decl meth_info)
| CXXConstructorDecl meth_info -> CXXConstructorDecl (get_updated_method_decl meth_info)
| ObjCMethodDecl (decl_info', name, obj_c_method_decl_info) ->
let body' =
Option.map (stmt_process_locs loc_composer) obj_c_method_decl_info.omdi_body in
let obj_c_method_decl_info' = { obj_c_method_decl_info with omdi_body = body' } in
ObjCMethodDecl (decl_info', name, obj_c_method_decl_info')
| VarDecl (decl_info, string, type_ptr, var_decl_info) ->
let vdi_init_expr' =
Option.map (stmt_process_locs loc_composer) var_decl_info.vdi_init_expr in
let var_decl_info' =
{ var_decl_info with vdi_init_expr = vdi_init_expr' } in
VarDecl (decl_info, string, type_ptr, var_decl_info')
| _ ->
decl'
(** Process locations in the AST by making them explicit.
Each toplevel declaration determines the current file,
and once diving into the details of the declaration, location
information about other (include) files is ignored. *)
let ast_decl_process_locs loc_composer ast_decl =
let toplevel_decl_process_locs decl =
let decl_info = Clang_ast_proj.get_decl_tuple decl in
LocComposer.set_current_file loc_composer decl_info.Clang_ast_t.di_source_range;
decl_process_locs loc_composer decl in
match ast_decl with
| Clang_ast_t.TranslationUnitDecl (decl_info, decl_list, decl_context_info, type_list) ->
let decl_list' = IList.map toplevel_decl_process_locs decl_list in
Clang_ast_t.TranslationUnitDecl (decl_info, decl_list', decl_context_info, type_list)
| _ ->
assert false
let preprocess_ast_decl ast_decl =
let loc_composer = LocComposer.create () in
ast_decl_process_locs loc_composer ast_decl

@ -1,18 +0,0 @@
(*
* 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.
*)
(** Module to preprocess location information in the AST.
The original location information is incremental, each location is a delta
w.r.t. the previous one. This module processes the AST and makes locations explicit. *)
(** Pretty print an AST. *)
val pp_ast_decl : Format.formatter -> Clang_ast_t.decl -> unit
(** Preprocess the AST to make locations explicit. *)
val preprocess_ast_decl : Clang_ast_t.decl -> Clang_ast_t.decl

@ -97,18 +97,14 @@ let do_run source_path ast_path =
| Some path -> path, validate_decl_from_file path
| None -> "stdin of " ^ source_path, validate_decl_from_stdin () in
let ast_decl' = CAstProcessor.preprocess_ast_decl ast_decl in
Printing.log_out "Original AST@.%a@." CAstProcessor.pp_ast_decl ast_decl;
Printing.log_out "AST with explicit locations:@.%a@." CAstProcessor.pp_ast_decl ast_decl';
let decl_index, _, type_index = Clang_ast_main.index_node_pointers ast_decl' in
let decl_index, _, type_index = Clang_ast_main.index_node_pointers ast_decl in
CFrontend_config.pointer_decl_index := decl_index;
CFrontend_config.pointer_type_index := type_index;
CFrontend_config.json := ast_filename;
CLocation.check_source_file source_path;
let source_file = CLocation.source_file_from_path source_path in
print_endline ("Start translation of AST from " ^ !CFrontend_config.json);
CFrontend.do_source_file source_file ast_decl';
CFrontend.do_source_file source_file ast_decl;
print_endline ("End translation AST file " ^ !CFrontend_config.json ^ "... OK!")
with
(Yojson.Json_error s) as exc -> Printing.log_err "%s\n" s;

@ -7,11 +7,11 @@ digraph iCFG {
7 -> 4 ;
6 [label="6: Prune (false branch) \n PRUNE((1 == 0), false); [line 12]\n " shape="invhouse"]
6 [label="6: Prune (false branch) \n PRUNE((1 == 0), false); [line 14]\n " shape="invhouse"]
6 -> 3 ;
5 [label="5: Prune (true branch) \n PRUNE((1 != 0), true); [line 12]\n " shape="invhouse"]
5 [label="5: Prune (true branch) \n PRUNE((1 != 0), true); [line 14]\n " shape="invhouse"]
5 -> 7 ;

@ -14,7 +14,7 @@ digraph iCFG {
14 -> 17 ;
13 [label="13: Call _fun___infer_assume \n n$10=*&name:class NSString * [line -1]\n n$11=_fun___infer_assume((n$10 != 0):class NSString *) [line -1]\n REMOVE_TEMPS(n$10,n$11); [line -1]\n " shape="box"]
13 [label="13: Call _fun___infer_assume \n n$10=*&name:class NSString * [line 31]\n n$11=_fun___infer_assume((n$10 != 0):class NSString *) [line 31]\n REMOVE_TEMPS(n$10,n$11); [line 31]\n " shape="box"]
13 -> 12 ;
@ -29,7 +29,7 @@ digraph iCFG {
10 -> 13 ;
9 [label="9: Call _fun___infer_assume \n n$5=*&a:class A * [line -1]\n n$6=_fun___infer_assume((n$5 != 0):class A *) [line -1]\n REMOVE_TEMPS(n$5,n$6); [line -1]\n " shape="box"]
9 [label="9: Call _fun___infer_assume \n n$5=*&a:class A * [line 37]\n n$6=_fun___infer_assume((n$5 != 0):class A *) [line 37]\n REMOVE_TEMPS(n$5,n$6); [line 37]\n " shape="box"]
9 -> 8 ;

Loading…
Cancel
Save