@ -66,44 +66,29 @@ let add_predefined_types tenv =
add_predefined_objc_types tenv ;
add_predefined_basic_types tenv
let rec search_for_named_type tenv typ =
let search typename =
match typename with
| Sil . TN_typedef name ->
( match Sil . tenv_lookup tenv typename with
| Some _ -> typename
| None ->
let pot_class_type = Sil . TN_csu ( Sil . Class , name ) in
match Sil . tenv_lookup tenv pot_class_type with
| Some _ -> pot_class_type
| None ->
let pot_protocol_type = Sil . TN_csu ( Sil . Protocol , name ) in
match Sil . tenv_lookup tenv pot_protocol_type with
| Some _ -> pot_protocol_type
| None ->
let pot_struct_type = Sil . TN_csu ( Sil . Struct , name ) in
match Sil . tenv_lookup tenv pot_struct_type with
| Some _ -> pot_struct_type
| None ->
let pot_union_type = Sil . TN_csu ( Sil . Union , name ) in
match Sil . tenv_lookup tenv pot_union_type with
| Some _ -> pot_union_type
| None -> raise Typename_not_found )
| _ -> typename in
match typ with
| Sil . Tvar typename -> Sil . Tvar ( search typename )
| Sil . Tptr ( typ , p ) ->
Sil . Tptr ( search_for_named_type tenv typ , p )
| _ -> typ
let parse_func_type name func_type = None
let create_csu opt_type =
match opt_type with
| ` Type s ->
( let buf = Str . split ( Str . regexp " [ \t ]+ " ) s in
match buf with
| " struct " :: l -> Sil . Struct , General_utils . string_from_list l
| " class " :: l -> Sil . Class , General_utils . string_from_list l
| " union " :: l -> Sil . Union , General_utils . string_from_list l
| _ -> Sil . Struct , s )
| _ -> assert false
(* We need to take the name out of the type as the struct can be anonymous *)
let get_record_name opt_type = match opt_type with
| ` Type n' -> CTypes . cut_struct_union n'
| ` NoType -> assert false
let get_record_name_csu opt_type name_info =
let name_str = name_info . Clang_ast_t . ni_name in
let csu , type_name = create_csu opt_type in
let prefix = Ast_utils . get_qualifier_string name_info in
let name =
if ( String . length name_str = 0 ) then prefix ^ type_name else prefix ^ name_str in
csu , name
let get_record_name opt_type name_info =
snd ( get_record_name_csu opt_type name_info )
let get_method_decls parent decl_list =
let open Clang_ast_t in
@ -115,64 +100,31 @@ let get_method_decls parent decl_list =
and traverse_decl_list parent decl_list = list_flatten ( list_map ( traverse_decl parent ) decl_list ) in
traverse_decl_list parent decl_list
(* In case of typedef like *)
(* typedef struct { f1; f2; ... } s; *)
(* the AST-dump splits the typedef definition from the struct definition. *)
(* The type in the typedef "s" will be "s" and this become detached from the struct definition. *)
(* To avoid circular entry in tenv, we disambiguate this case. *)
(* We check if in tenv there is a "strucs s" defined and we make the type def "s" *)
(* point directly to "struct s" *)
let rec disambiguate_typedef tenv namespace t mn =
match t with
| Sil . Tvar ( Sil . TN_typedef mn' ) ->
if ( Mangled . equal mn mn' ) then
(* This will give a circularity in the definition of typedef in the tenv. *)
(* Eg. TN_typdef ( mn ) --> TN_typedef ( mn ) . We need to break it *)
let tn = Sil . TN_csu ( Sil . Struct , mn ) in
( match Sil . tenv_lookup tenv tn with
| Some _ ->
(* There is a struct in tenv, so we make the typedef mn pointing to the struct *)
Printing . log_out " ...Found type TN_typdef('%s') " ( Mangled . to_string mn ) ;
Printing . log_out " in typedef of '%s'@. " ( Mangled . to_string mn ) ;
Printing . log_out
" Avoid circular definition in tenv by pointing the typedef to struc TN_csu('%s')@. "
( Mangled . to_string mn ) ;
Sil . Tvar ( tn )
| None ->
if add_late_defined_record tenv namespace tn then
disambiguate_typedef tenv namespace t mn
else t )
else t
| _ -> t
and opt_type_to_sil_type tenv opt_type =
match opt_type with
| ` Type ( s ) -> qual_type_to_sil_type tenv ( Ast_expressions . create_qual_type s )
| ` NoType -> Sil . Tvoid
let get_class_methods tenv class_name namespace decl_list =
let process_method_decl = function
| Clang_ast_t . CXXMethodDecl ( decl_info , name_info , qual_type , function_decl_info ) ->
let method_name = name_info . Clang_ast_t . ni_name in
Printing . log_out " ...Declaring method '%s'. \n " method_name ;
let typ = CTypes . get_type qual_type in
let method_proc = General_utils . mk_procname_from_cpp_method class_name method_name typ in
Some method_proc
| _ -> None in
(* poor mans list_filter_map *)
list_flatten_options ( list_map process_method_decl decl_list )
and do_typedef_declaration tenv namespace decl_info name opt_type typedef_decl_info =
if name = CFrontend_config . class_type | | name = CFrontend_config . id_cl then ()
else
let ns_suffix = Ast_utils . namespace_to_string namespace in
let name = ns_suffix ^ name in
let mn = Mangled . from_string name in
let typename = Sil . TN_typedef ( mn ) in
let t = opt_type_to_sil_type tenv opt_type in
(* check for ambiguities in typedef that may create circularities in tenv *)
let typ = disambiguate_typedef tenv namespace t mn in
Printing . log_out " ADDING: TypedefDecl for '%s' " name ;
Printing . log_out " with type '%s' \n " ( Sil . typ_to_string typ ) ;
Printing . log_out " ...Adding entry to tenv with Typename TN_typedef = '%s' \n "
( Sil . typename_to_string typename ) ;
Sil . tenv_add tenv typename typ
let add_struct_to_tenv tenv typ =
let csu = match typ with
| Sil . Tstruct ( _ , _ , csu , _ , _ , _ , _ ) -> csu
| _ -> assert false in
let mangled = CTypes . get_name_from_struct typ in
let typename = Sil . TN_csu ( csu , mangled ) in
Sil . tenv_add tenv typename typ
and get_struct_fields tenv record_name namespace decl_list =
let rec get_struct_fields tenv record_name namespace decl_list =
let open Clang_ast_t in
let do_one_decl decl = match decl with
| FieldDecl ( _ , name_info , qual_type , _ ) ->
let field_name = name_info . Clang_ast_t . ni_name in
Printing . log_out " ...Defining field '%s'. \n " field_name ;
let id = General_utils . mk_class_field_name record_name field_name in
let id = General_utils . mk_class_field_name record_name name_info . Clang_ast_t . ni_name in
let typ = qual_type_to_sil_type tenv qual_type in
let annotation_items = [] in (* For the moment we don't use them *)
[ ( id , typ , annotation_items ) ]
@ -182,163 +134,46 @@ and get_struct_fields tenv record_name namespace decl_list =
| _ -> [] in
list_flatten ( list_map do_one_decl decl_list )
and get_class_methods tenv class_name namespace decl_list =
let process_method_decl = function
| Clang_ast_t . CXXMethodDecl ( decl_info , name_info , qual_type , function_decl_info ) ->
let method_name = name_info . Clang_ast_t . ni_name in
Printing . log_out " ...Declaring method '%s'. \n " method_name ;
let method_proc = General_utils . mk_procname_from_cpp_method class_name method_name ( CTypes . get_type qual_type ) in
Some method_proc
| _ -> None in
(* poor mans list_filter_map *)
list_flatten_options ( list_map process_method_decl decl_list )
(* For a record declaration it returns/constructs the type *)
and get_declaration_type tenv namespace decl =
let open Clang_ast_t in
match decl with
| CXXRecordDecl ( decl_info , name_info , opt_type , type_ptr , decl_list , _ , record_decl_info , _ )
| RecordDecl ( decl_info , name_info , opt_type , type_ptr , decl_list , _ , record_decl_info ) ->
let csu , name = get_record_name_csu opt_type name_info in
let mangled_name = Mangled . from_string name in
let sil_typename = Sil . Tvar ( Sil . TN_csu ( csu , mangled_name ) ) in
(* temporarily saves the type name to avoid infinite loops in recursive types *)
Ast_utils . update_sil_types_map type_ptr sil_typename ;
if not record_decl_info . Clang_ast_t . rdi_is_complete_definition then
Printing . log_err
" ...Warning, definition incomplete. The full definition will probably be later \n @. " ;
let non_static_fields = get_struct_fields tenv name namespace decl_list in
let non_static_fields' = if CTrans_models . is_objc_memory_model_controlled name then
General_utils . append_no_duplicates_fields [ Sil . objc_ref_counter_field ] non_static_fields
else non_static_fields in
let sorted_non_static_fields = CFrontend_utils . General_utils . sort_fields non_static_fields' in
let static_fields = [] in (* Warning for the moment we do not treat static field. *)
let methods = get_class_methods tenv name namespace decl_list in (* C++ methods only *)
let superclasses = [] in
let item_annotation = Sil . item_annotation_empty in (* No annotations for struts *)
let sil_type = Sil . Tstruct ( sorted_non_static_fields , static_fields , csu , Some mangled_name ,
superclasses , methods , item_annotation ) in
Ast_utils . update_sil_types_map type_ptr sil_type ;
sil_type
| _ -> assert false
and add_types_from_decl_to_tenv tenv namespace decl =
let typ = get_declaration_type tenv namespace decl in
let typ = expand_structured_type tenv typ in
add_struct_to_tenv tenv typ ;
typ
(* For a record declaration it returns/constructs the type *)
and get_declaration_type tenv namespace decl =
let open Clang_ast_t in
let n , opt_type , decl_list = match decl with
| CXXRecordDecl ( decl_info , name_info , opt_type , _ , decl_list , _ , record_decl_info , _ )
| RecordDecl ( decl_info , name_info , opt_type , _ , decl_list , _ , record_decl_info ) ->
let ptr = decl_info . Clang_ast_t . di_pointer in
let name = name_info . Clang_ast_t . ni_name in
Printing . log_out " ADDING: RecordDecl for '%s' " name ;
Printing . log_out " pointer= '%s' \n " ptr ;
if not record_decl_info . Clang_ast_t . rdi_is_complete_definition then
Printing . log_err " ...Warning, definition incomplete. The full definition will probably be later \n @. " ;
name , opt_type , decl_list
| _ -> assert false in
let ns_suffix = Ast_utils . namespace_to_string namespace in
let n = ns_suffix ^ n in
let name_str = get_record_name opt_type in
Printing . log_out " Record Declaration '%s' defined as struct \n " n ;
let non_static_fields = get_struct_fields tenv name_str namespace decl_list in
let non_static_fields = if CTrans_models . is_objc_memory_model_controlled n then
General_utils . append_no_duplicates_fields [ Sil . objc_ref_counter_field ] non_static_fields
else non_static_fields in
let non_static_fields = CFrontend_utils . General_utils . sort_fields non_static_fields in
let static_fields = [] in (* Warning for the moment we do not treat static field. *)
let typ = ( match opt_type with
| ` Type s -> qual_type_to_sil_type tenv ( Ast_expressions . create_qual_type s )
| _ -> assert false ) in
let csu = ( match typ with
| Sil . Tvar ( Sil . TN_csu ( csu , _ ) ) -> csu
| _ -> Sil . Struct ) in
let name = Some ( Mangled . from_string name_str ) in
let methods_list = get_class_methods tenv name_str namespace decl_list in (* C++ methods only *)
let superclass_list = [] in
let item_annotation = Sil . item_annotation_empty in (* No annotations for struts *)
Sil . Tstruct
( non_static_fields , static_fields , csu , name , superclass_list , methods_list , item_annotation )
(* Look for a record definition that is defined after it is dereferenced. *)
(* It returns true if a new record definition has been added to tenv. *)
and add_late_defined_record tenv namespace typename =
Printing . log_out " !!!! Calling late-defined record '%s' \n " ( Sil . typename_to_string typename ) ;
match typename with
| Sil . TN_csu ( Sil . Struct , name ) | Sil . TN_csu ( Sil . Union , name ) ->
let open Clang_ast_t in
let rec scan decls =
match decls with
| [] -> false
| ( CXXRecordDecl ( _ , _ , opt_type , _ , _ , _ , record_decl_info , _ ) as d ) :: decls'
| ( RecordDecl ( _ , _ , opt_type , _ , _ , _ , record_decl_info ) as d ) :: decls' ->
( match opt_type with
| ` Type t ->
(* the string t contains the name of the type preceded by the word struct. *)
let t_no_struct = CTypes . cut_struct_union t in
let pot_struct_type = Sil . TN_csu ( Sil . Struct , ( Mangled . from_string t_no_struct ) ) in
let pot_union_type = Sil . TN_csu ( Sil . Union , ( Mangled . from_string t_no_struct ) ) in
if ( Sil . typename_equal typename pot_struct_type | |
Sil . typename_equal typename pot_union_type ) &&
record_decl_info . Clang_ast_t . rdi_is_complete_definition then (
Printing . log_out " !!!! Adding late-defined record '%s' \n " t ;
ignore ( add_types_from_decl_to_tenv tenv namespace d ) ;
true )
else scan decls'
| _ -> scan decls' )
| LinkageSpecDecl ( _ , decl_list' , _ ) :: decls' -> scan ( decl_list' @ decls' )
| _ :: decls' -> scan decls' in
scan ! CFrontend_config . global_translation_unit_decls
| _ -> false
(* Look for a typedef definition that is defined after it is used. *)
(* It returns true if a new typedef definition has been added to tenv. *)
and add_late_defined_typedef tenv namespace typename =
Printing . log_out " Calling late-defined typedef '%s' \n " ( Sil . typename_to_string typename ) ;
match typename with
| Sil . TN_typedef name ->
let rec scan decls =
let open Clang_ast_t in
match decls with
| [] -> false
| TypedefDecl ( decl_info , name_info , opt_type , _ , tdi ) :: decls' ->
let name' = name_info . Clang_ast_t . ni_name in
( match opt_type with
| ` Type t ->
if ( Mangled . to_string name ) = name' then (
Printing . log_out " !!!! Adding late-defined typedef '%s' \n " t ;
do_typedef_declaration tenv namespace decl_info name' opt_type tdi ;
true )
else scan decls'
| _ -> scan decls' )
| LinkageSpecDecl ( _ , decl_list' , _ ) :: decls' -> scan ( decl_list' @ decls' )
| _ :: decls' -> scan decls' in
scan ! CFrontend_config . global_translation_unit_decls
| _ -> false
(* Expand a named type Tvar if it has a definition in tenv. This is used for Tenum, Tstruct, etc. *)
and expand_structured_type tenv typ =
match typ with
| Sil . Tvar tn ->
( match Sil . tenv_lookup tenv tn with
| Some t ->
Printing . log_out
" Type expanded with type '%s' found in tenv@. " ( Sil . typ_to_string t ) ;
if Sil . typ_equal t typ then
typ
else expand_structured_type tenv t
| None -> if ( add_late_defined_record tenv None tn | |
add_late_defined_typedef tenv None tn ) then
expand_structured_type tenv typ
else typ )
| Sil . Tptr ( t , _ ) -> typ (* do not expand types under pointers *)
| _ -> typ
and add_struct_to_tenv tenv typ =
let typ = expand_structured_type tenv typ in
let csu = match typ with
| Sil . Tstruct ( _ , _ , csu , _ , _ , _ , _ ) -> csu
| _ -> assert false in
let mangled = CTypes . get_name_from_struct typ in
let typename = Sil . TN_csu ( csu , mangled ) in
Printing . log_out " >>>Adding struct to tenv mangled='%s' \n " ( Mangled . to_string mangled ) ;
Printing . log_out " >>>Adding struct to tenv typ='%s' \n " ( Sil . typ_to_string typ ) ;
Printing . log_out " >>>with Key Typename TN_csu('%s') \n " ( Sil . typename_to_string typename ) ;
Printing . log_out " >>>Adding entry to tenv ('%s', " ( Sil . typename_to_string typename ) ;
Printing . log_out " '%s') \n " ( Sil . typ_to_string typ ) ;
Sil . tenv_add tenv typename typ ;
Printing . log_out " >>>Verifying that Typename TN_csu('%s') is in tenv \n "
( Sil . typename_to_string typename ) ;
( match Sil . tenv_lookup tenv typename with
| Some t -> Printing . log_out " >>>OK. Found typ='%s' \n " ( Sil . typ_to_string t )
| None -> Printing . log_out " >>>NOT Found!! \n " )
(* Translate a qual_type from clang to sil type. *)
and qual_type_to_sil_type tenv qt =
CType_to_sil_type . qual_type_to_sil_type add_types_from_decl_to_tenv tenv qt
and qual_type_to_sil_type_np tenv qt =
qual_type_to_sil_type tenv qt
and type_name_to_sil_type tenv name =
qual_type_to_sil_type tenv ( Ast_expressions . create_ qual _type name )
let type_name_to_sil_type tenv name =
qual_type_to_sil_type tenv ( Ast_expressions . create_class_type name )
let get_type_from_expr_info ei tenv =
let qt = ei . Clang_ast_t . ei_qual_type in
@ -364,4 +199,4 @@ let extract_sil_type_from_stmt tenv s =
let get_type_curr_class tenv curr_class_opt =
let name = CContext . get_curr_class_name curr_class_opt in
let typ = Sil . Tvar ( Sil . TN_csu ( Sil . Class , ( Mangled . from_string name ) ) ) in
expand_structured_type tenv typ
CTypes . expand_structured_type tenv typ