From 51e0e40bc74bfde7dbcbd1f96cdd9a9c8acc1ccc Mon Sep 17 00:00:00 2001 From: Dulma Rodriguez Date: Tue, 15 Sep 2015 09:31:54 -0100 Subject: [PATCH] [clang] [2 of 3] Dealing with custom ast expressions and flow of types in the frontend. Summary: This is the second of 3 stack diffs to deal with replacing the parser of types. This diff is about general changes to the frontend to make it cope with the change. There are two main challenges: 1. We create pieces of ast in ast_expressions, such as getters and setters. For that we create custom types. 2. We store types in cMethod_signature for parameters and return type of functions. This was stored as strings, but that means losing the pointer information which is vital to get the sil types. So this diff consists mostly of dealing with these challenges. It change the signature of cMethod_signature and update modules accordingly. To deal with the custom types, we build methods in ast_expressions for creating those types, with a custom type pointer, like "internal_typeint". At the beginning of the translation we save all these custom types in the map from type pointers to sil types that we build as we compute the types, so that they are available later. Another custom type that we build is a type of classes or pointer of classes based on the current class. I found a simple way to deal with it, giving it a pointer "class_name", and then we know how to translate those. Something I tried is to save the declaration of the current class and pass that declaration around, but somehow that lead to pref regression, so I removed it in favor of this more lightweight version. --- infer/src/clang/ast_expressions.ml | 127 ++++++++++++++++++-------- infer/src/clang/ast_expressions.mli | 30 +++++- infer/src/clang/cContext.ml | 3 - infer/src/clang/cContext.mli | 2 - infer/src/clang/cFrontend_config.ml | 4 + infer/src/clang/cFrontend_config.mli | 4 + infer/src/clang/cMethod_signature.ml | 11 ++- infer/src/clang/cMethod_signature.mli | 10 +- infer/src/clang/cMethod_trans.ml | 42 +++++---- infer/src/clang/cTrans.ml | 21 +++-- infer/src/clang/cTrans_models.ml | 16 ++-- infer/src/clang/cTrans_utils.ml | 7 +- infer/src/clang/cTypes.ml | 14 --- infer/src/clang/cTypes.mli | 2 - infer/src/clang/cTypes_decl.ml | 49 ++++++++-- infer/src/clang/objcProperty_decl.ml | 5 +- 16 files changed, 227 insertions(+), 120 deletions(-) diff --git a/infer/src/clang/ast_expressions.ml b/infer/src/clang/ast_expressions.ml index 1d783ec81..aeb029fbc 100644 --- a/infer/src/clang/ast_expressions.ml +++ b/infer/src/clang/ast_expressions.ml @@ -83,34 +83,78 @@ let create_qual_type s = { qt_type_ptr = Ast_utils.get_invalid_pointer (); } -let create_pointer_type s = - create_qual_type (s^" *") +let create_qual_type_with_just_pointer pointer = + { + Clang_ast_t.qt_raw = ""; + qt_desugared = None; + qt_type_ptr = pointer; + } -let create_int_type () = create_qual_type "int" +let get_constant_qual_type s = + let pointer = CFrontend_config.type_pointer_prefix ^ s in + { + Clang_ast_t.qt_raw = s; + qt_desugared = None; + qt_type_ptr = pointer + } -let create_void_type () = create_qual_type "void *" +(* Whenever new type are added manually to the translation here, *) +(* they should be added to the map in cTypes_decl too!! *) +let create_int_type = + get_constant_qual_type "int" -let create_id_type () = create_qual_type "id" +let create_void_type = + get_constant_qual_type "void" -let create_char_type () = create_qual_type "char *" +let create_void_star_type = + get_constant_qual_type "void *" -(* pointer needs to be set when we start using these, non trivial to do though *) -let create_BOOL_type () = { - Clang_ast_t.qt_raw = "BOOL"; - qt_desugared = Some ("signed char"); - qt_type_ptr = Ast_utils.get_invalid_pointer (); -} +let create_id_type = + get_constant_qual_type CFrontend_config.id_cl + +let create_nsarray_star_type = + get_constant_qual_type (CFrontend_config.nsarray_cl ^ " *") + +let create_char_star_type = + get_constant_qual_type "char *" + +let create_BOOL_type = + get_constant_qual_type "signed char" -let create_void_unsigned_long_type () = create_qual_type "void *(unsigned long)" +let create_unsigned_long_type = + get_constant_qual_type "unsigned long" -let create_unsigned_long_type () = create_qual_type "unsigned long" +let create_void_unsigned_long_type = + get_constant_qual_type "void *(unsigned long)" -let create_void_void_type () = create_qual_type "void (void *)" +let create_void_void_type = + get_constant_qual_type "void (void *)" + +let create_class_type class_name = + { + Clang_ast_t.qt_raw = ""; + qt_desugared = None; + qt_type_ptr = "custom_class_name*" ^ class_name; + } + +let create_struct_type struct_name = + { + Clang_ast_t.qt_raw = ""; + qt_desugared = None; + qt_type_ptr = "custom_struct_name*" ^ struct_name; + } + +let create_pointer_type class_type = + { + Clang_ast_t.qt_raw = ""; + qt_desugared = None; + qt_type_ptr = "custom_pointer_"^class_type.Clang_ast_t.qt_type_ptr + } let create_integer_literal stmt_info n = let stmt_info = dummy_stmt_info () in let expr_info = { - Clang_ast_t.ei_qual_type = create_int_type (); + Clang_ast_t.ei_qual_type = create_int_type; ei_value_kind = `RValue; ei_object_kind = `Ordinary; } in @@ -123,7 +167,7 @@ let create_integer_literal stmt_info n = let create_cstyle_cast_expr stmt_info stmts qt = let expr_info = { - Clang_ast_t.ei_qual_type = create_void_type (); + Clang_ast_t.ei_qual_type = create_void_type; ei_value_kind = `RValue; ei_object_kind = `Ordinary; } in @@ -135,7 +179,7 @@ let create_cstyle_cast_expr stmt_info stmts qt = let create_parent_expr stmt_info stmts = let expr_info = { - Clang_ast_t.ei_qual_type = create_void_type (); + Clang_ast_t.ei_qual_type = create_void_type; ei_value_kind = `RValue; ei_object_kind = `Ordinary; } in @@ -155,10 +199,9 @@ let create_implicit_cast_expr stmt_info stmts typ cast_kind = let create_nil stmt_info = let integer_literal = create_integer_literal stmt_info "0" in - let cstyle_cast_expr = create_cstyle_cast_expr stmt_info [integer_literal] (create_int_type ()) in + let cstyle_cast_expr = create_cstyle_cast_expr stmt_info [integer_literal] create_int_type in let paren_expr = create_parent_expr stmt_info [cstyle_cast_expr] in - let implicit_cast_expr = create_implicit_cast_expr stmt_info [paren_expr] (create_id_type ()) `NullToPointer in - implicit_cast_expr + create_implicit_cast_expr stmt_info [paren_expr] create_id_type `NullToPointer let dummy_stmt () = let pointer = Ast_utils.get_fresh_pointer () in @@ -201,7 +244,7 @@ let make_obj_c_message_expr_info_instance sel = { let make_obj_c_message_expr_info_class selector qt = { Clang_ast_t.omei_selector = selector; - omei_receiver_kind = `Class (create_qual_type qt); + omei_receiver_kind = `Class (create_class_type qt); omei_is_definition_found = false; omei_decl_pointer = None (* TODO look into it *) } @@ -262,7 +305,7 @@ let make_cast_expr qt di decl_ref_expr_info objc_kind = (* Build AST expression self.field_name as `LValue *) let make_self_field class_type di qt field_name = - let qt_class = create_qual_type class_type in + let qt_class = create_pointer_type (create_class_type class_type) in let expr_info = make_expr_info_with_objc_kind qt `ObjCProperty in let stmt_info = make_stmt_info di in let cast_exp = make_cast_expr qt_class di (make_decl_ref_expr_info (make_decl_ref_self di.Clang_ast_t.di_pointer qt_class)) `ObjCProperty in @@ -310,7 +353,7 @@ let make_general_expr_info qt vk ok = { } let make_ObjCBoolLiteralExpr stmt_info value = - let ei = make_expr_info (create_BOOL_type ()) in + let ei = make_expr_info create_BOOL_type in Clang_ast_t.ObjCBoolLiteralExpr((fresh_stmt_info stmt_info),[], ei, value) let make_decl_ref_exp_var (var_name, var_qt, var_ptr) var_kind stmt_info = @@ -354,7 +397,7 @@ let make_next_object_exp stmt_info item items = Clang_ast_t.DeclRefExpr (stmt_info_var, [], expr_info, decl_ref_expr_info), var_type | _ -> assert false in - let message_call = make_message_expr (create_qual_type CFrontend_config.id_cl) + let message_call = make_message_expr create_id_type CFrontend_config.next_object items stmt_info false in let boi = { Clang_ast_t.boi_kind = `Assign } in make_binary_stmt var_decl_ref message_call stmt_info (make_expr_info_with_objc_kind var_type `ObjCProperty) boi @@ -386,7 +429,7 @@ let translate_dispatch_function block_name stmt_info stmt_list ei n = let block_var_decl = VarDecl(decl_info, block_name_info, ei.ei_qual_type, var_decl_info) in let decl_stmt = DeclStmt(stmt_info,[], [block_var_decl]) in - let expr_info_call = make_general_expr_info (create_void_type ()) `XValue `Ordinary in + let expr_info_call = make_general_expr_info create_void_type `XValue `Ordinary in let expr_info_dre = make_expr_info_with_objc_kind qt `Ordinary in let decl_ref = make_decl_ref_qt `Var stmt_info.si_pointer block_name false qt in let decl_ref_expr_info = make_decl_ref_expr_info decl_ref in @@ -412,8 +455,7 @@ let build_OpaqueValueExpr si source_expr ei = let opaque_value_expr_info = { Clang_ast_t.ovei_source_expr = Some source_expr } in Clang_ast_t.OpaqueValueExpr (si, [], ei, opaque_value_expr_info) -let pseudo_object_qt () = - create_qual_type CFrontend_config.pseudo_object_type +let pseudo_object_qt () = create_class_type CFrontend_config.pseudo_object_type (* Create expression PseudoObjectExpr for 'o.m' *) let build_PseudoObjectExpr qt_m o_cast_decl_ref_exp mname = @@ -436,7 +478,7 @@ let build_PseudoObjectExpr qt_m o_cast_decl_ref_exp mname = let create_call stmt_info decl_pointer function_name qt parameters = let expr_info_call = { - Clang_ast_t.ei_qual_type = create_void_type (); + Clang_ast_t.ei_qual_type = create_void_type; ei_value_kind = `XValue; ei_object_kind = `Ordinary } in @@ -502,12 +544,15 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = let build_stop pstop = match pstop with | Clang_ast_t.ParmVarDecl (di, name, qt, _) -> - let qt_fun = create_void_unsigned_long_type () in + let qt_fun = create_void_unsigned_long_type in + let type_opt = Some create_BOOL_type in let parameter = Clang_ast_t.UnaryExprOrTypeTraitExpr ((fresh_stmt_info stmt_info), [], - make_expr_info (create_unsigned_long_type ()), - { Clang_ast_t.uttei_kind = `SizeOf; Clang_ast_t.uttei_qual_type = Some (create_BOOL_type ()) }) in - let malloc = create_call (fresh_stmt_info stmt_info) di.Clang_ast_t.di_pointer CFrontend_config.malloc qt_fun [parameter] in + make_expr_info create_unsigned_long_type, + { Clang_ast_t.uttei_kind = `SizeOf; Clang_ast_t.uttei_qual_type = type_opt}) in + let pointer = di.Clang_ast_t.di_pointer in + let stmt_info = fresh_stmt_info stmt_info in + let malloc = create_call stmt_info pointer CFrontend_config.malloc qt_fun [parameter] in let init_exp = create_implicit_cast_expr (fresh_stmt_info stmt_info) [malloc] qt `BitCast in make_DeclStmt (fresh_stmt_info stmt_info) di qt name (Some init_exp) | _ -> assert false in @@ -529,11 +574,11 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = let free_stop pstop = match pstop with | Clang_ast_t.ParmVarDecl (di, name, qt, _) -> - let qt_fun = create_void_void_type () in + let qt_fun = create_void_void_type in let decl_ref = make_decl_ref_qt `Var di.Clang_ast_t.di_pointer name.Clang_ast_t.ni_name false qt in let cast = cast_expr decl_ref qt in let parameter = - create_implicit_cast_expr (fresh_stmt_info stmt_info) [cast] (create_void_type ()) `BitCast in + create_implicit_cast_expr (fresh_stmt_info stmt_info) [cast] create_void_type `BitCast in create_call (fresh_stmt_info stmt_info) di.Clang_ast_t.di_pointer CFrontend_config.free qt_fun [parameter] | _ -> assert false in @@ -542,7 +587,8 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = let idx_decl_stmt, idx_decl_ref_exp, idx_cast, idx_qt = build_idx_decl pidx in let rhs = build_PseudoObjectExpr idx_qt array_decl_ref_exp CFrontend_config.count in let lt = { Clang_ast_t.boi_kind = `LT } in - Clang_ast_t.BinaryOperator (fresh_stmt_info stmt_info, [idx_cast; rhs], make_expr_info (create_int_type ()), lt) in + let exp_info = make_expr_info create_int_type in + Clang_ast_t.BinaryOperator (fresh_stmt_info stmt_info, [idx_cast; rhs], exp_info, lt) in (* idx++ *) let un_op idx_decl_ref_expr qt_idx = @@ -579,7 +625,7 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = (* NSArray *objects = a *) let objects_array_DeclStmt init = let di = { empty_decl_info with Clang_ast_t.di_pointer = Ast_utils.get_fresh_pointer () } in - let qt = create_qual_type CFrontend_config.ns_array_ptr in + let qt = create_pointer_type (create_class_type CFrontend_config.nsarray_cl) in (* init should be ImplicitCastExpr of array a *) let vdi = { empty_var_decl_info with Clang_ast_t.vdi_init_expr = Some (init) } in let var_decl = Clang_ast_t.VarDecl (di, make_name_decl CFrontend_config.objects, qt, vdi) in @@ -611,12 +657,12 @@ let translate_block_enumerate block_name stmt_info stmt_list ei = let make_block_call block_qt object_cast idx_cast stop_cast = let decl_ref = make_decl_ref_invalid `Var block_name false block_qt in let fun_cast = cast_expr decl_ref block_qt in - let ei_call = make_expr_info (create_void_type ()) in + let ei_call = make_expr_info create_void_type in Clang_ast_t.CallExpr (fresh_stmt_info stmt_info, [fun_cast; object_cast; idx_cast; stop_cast], ei_call) in (* build statement "if (stop) break;" *) let build_if_stop stop_cast = - let bool_qt = create_BOOL_type () in + let bool_qt = create_BOOL_type in let ei = make_expr_info bool_qt in let unary_op = Clang_ast_t.UnaryOperator (fresh_stmt_info stmt_info, [stop_cast], ei, { Clang_ast_t.uoi_kind = `Deref; uoi_is_postfix = true }) in let cond = create_implicit_cast_expr (fresh_stmt_info stmt_info) [unary_op] bool_qt `LValueToRValue in @@ -691,4 +737,5 @@ let create_assume_not_null_call decl_info var_name var_type = let null_expr = create_integer_literal stmt_info "0" in let bin_op = make_binary_stmt decl_ref_exp_cast null_expr stmt_info (make_lvalue_obc_prop_expr_info var_type) boi in let parameters = [bin_op] in - create_call stmt_info var_decl_ptr (Procname.to_string SymExec.ModelBuiltins.__infer_assume) (create_void_type ()) parameters + let procname = Procname.to_string SymExec.ModelBuiltins.__infer_assume in + create_call stmt_info var_decl_ptr procname create_void_type parameters diff --git a/infer/src/clang/ast_expressions.mli b/infer/src/clang/ast_expressions.mli index eede81d66..752b95089 100644 --- a/infer/src/clang/ast_expressions.mli +++ b/infer/src/clang/ast_expressions.mli @@ -23,7 +23,33 @@ val dummy_stmt_info : unit -> stmt_info val create_qual_type : string -> qual_type -val create_pointer_type : string -> qual_type +val create_char_star_type : qual_type + +val create_id_type : qual_type + +val create_nsarray_star_type : qual_type + +val create_void_type : qual_type + +val create_int_type : qual_type + +val create_void_star_type : qual_type + +val create_BOOL_type : qual_type + +val create_unsigned_long_type : qual_type + +val create_void_unsigned_long_type : qual_type + +val create_void_void_type : qual_type + +val create_class_type : string -> qual_type + +val create_struct_type : string -> qual_type + +val create_pointer_type : qual_type -> qual_type + +val create_qual_type_with_just_pointer : Clang_ast_t.pointer -> qual_type val make_objc_ivar_decl : decl_info -> qual_type -> obj_c_property_impl_decl_info -> string -> decl @@ -51,8 +77,6 @@ val create_nil : stmt_info -> stmt val create_implicit_cast_expr : stmt_info -> stmt list -> qual_type -> cast_kind -> stmt -val create_char_type : unit -> qual_type - val make_message_expr : qual_type -> string -> stmt -> stmt_info -> bool -> stmt val make_compound_stmt : stmt list -> stmt_info -> stmt diff --git a/infer/src/clang/cContext.ml b/infer/src/clang/cContext.ml index 7816c9c58..f35766a66 100644 --- a/infer/src/clang/cContext.ml +++ b/infer/src/clang/cContext.ml @@ -287,9 +287,6 @@ let curr_class_hash curr_class = | ContextProtocol name -> Hashtbl.hash name | ContextNoCls -> Hashtbl.hash "no class" -let get_qt_curr_class curr_class = - (get_curr_class_name curr_class)^" *" - let get_captured_vars context = context.captured_vars let create_curr_class tenv class_name = diff --git a/infer/src/clang/cContext.mli b/infer/src/clang/cContext.mli index 35bc2bd12..555d410fd 100644 --- a/infer/src/clang/cContext.mli +++ b/infer/src/clang/cContext.mli @@ -58,8 +58,6 @@ val get_curr_class : t -> curr_class val get_curr_class_name : curr_class -> string -val get_qt_curr_class : curr_class -> string - val curr_class_to_string : curr_class -> string val curr_class_compare : curr_class -> curr_class -> int diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 350fcb6d0..ce7345db1 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -161,3 +161,7 @@ let strong_attribtue = "__strong" let unsafe_unretained_attribute = "__unsafe_unretained" let autoreleasing_atribute = "__autoreleasing" + +let type_pointer_prefix = "internal_type" + +let nsarray_cl = "NSArray" diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index 99ab3e6d4..301694fd3 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -158,3 +158,7 @@ val strong_attribtue : string val unsafe_unretained_attribute : string val autoreleasing_atribute : string + +val type_pointer_prefix : string + +val nsarray_cl : string diff --git a/infer/src/clang/cMethod_signature.ml b/infer/src/clang/cMethod_signature.ml index d8770b5ad..180d83d91 100644 --- a/infer/src/clang/cMethod_signature.ml +++ b/infer/src/clang/cMethod_signature.ml @@ -12,8 +12,8 @@ type method_signature = { _name : Procname.t; - _args : (string * string * Clang_ast_t.stmt option) list; (* (name, type, default value) *) - _ret_type : string; + _args : (string * Clang_ast_t.qual_type * Clang_ast_t.stmt option) list; + _ret_type : Clang_ast_t.qual_type; _attributes : Clang_ast_t.attribute list; _loc : Clang_ast_t.source_range; _is_instance : bool; @@ -57,6 +57,9 @@ let replace_name_ms ms name = let ms_to_string ms = let gen = if ms._is_generated then " (generated)" else "" in - "Method "^(Procname.to_string ms._name)^gen^" "^ - (Utils.list_to_string (fun (s1, s2, _) -> s1^", "^s2) ms._args)^"->"^ms._ret_type^" "^ + "Method " ^ (Procname.to_string ms._name) ^ gen ^ " " ^ + Utils.list_to_string + (fun (s1, s2, _) -> s1 ^ ", " ^ (Clang_ast_j.string_of_qual_type s2)) + ms._args + ^ "->" ^ (Clang_ast_j.string_of_qual_type ms._ret_type) ^ " " ^ Clang_ast_j.string_of_source_range ms._loc diff --git a/infer/src/clang/cMethod_signature.mli b/infer/src/clang/cMethod_signature.mli index 4c0c13666..de21518f9 100644 --- a/infer/src/clang/cMethod_signature.mli +++ b/infer/src/clang/cMethod_signature.mli @@ -14,9 +14,10 @@ type method_signature val ms_get_name : method_signature -> Procname.t -val ms_get_args : method_signature -> (string * string * Clang_ast_t.stmt option) list +val ms_get_args : method_signature -> + (string * Clang_ast_t.qual_type * Clang_ast_t.stmt option) list -val ms_get_ret_type : method_signature -> string +val ms_get_ret_type : method_signature -> Clang_ast_t.qual_type val ms_get_attributes : method_signature -> Clang_ast_t.attribute list @@ -24,8 +25,9 @@ val ms_get_loc : method_signature -> Clang_ast_t.source_range val ms_is_instance : method_signature -> bool -val make_ms : Procname.t -> (string * string * Clang_ast_t.stmt option) list -> string -> Clang_ast_t.attribute list -> - Clang_ast_t.source_range -> bool -> bool -> method_signature +val make_ms : Procname.t -> (string * Clang_ast_t.qual_type * Clang_ast_t.stmt option) list -> + Clang_ast_t.qual_type -> Clang_ast_t.attribute list -> Clang_ast_t.source_range -> bool -> bool -> + method_signature val replace_name_ms : method_signature -> Procname.t -> method_signature diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 3d319922e..a6889e407 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -28,10 +28,10 @@ type method_call_type = | MCStatic type function_method_decl_info = - | Func_decl_info of Clang_ast_t.function_decl_info * string - | Cpp_Meth_decl_info of Clang_ast_t.function_decl_info * string (* class_name *) * string (* ret_type *) + | Func_decl_info of Clang_ast_t.function_decl_info * Clang_ast_t.qual_type + | Cpp_Meth_decl_info of Clang_ast_t.function_decl_info * string * Clang_ast_t.qual_type | ObjC_Meth_decl_info of Clang_ast_t.obj_c_method_decl_info * string - | Block_decl_info of Clang_ast_t.block_decl_info * string + | Block_decl_info of Clang_ast_t.block_decl_info * Clang_ast_t.qual_type let is_instance_method function_method_decl_info is_instance = match function_method_decl_info with @@ -44,8 +44,12 @@ let is_instance_method function_method_decl_info is_instance = let get_class_param function_method_decl_info = if (is_instance_method function_method_decl_info false) then match function_method_decl_info with - | Cpp_Meth_decl_info (_, class_name, _) -> [(CFrontend_config.this, class_name, None)] - | ObjC_Meth_decl_info (_, class_name) -> [(CFrontend_config.self, class_name, None)] + | Cpp_Meth_decl_info (_, class_name, _) -> + let class_type = Ast_expressions.create_struct_type class_name in + [(CFrontend_config.this, class_type, None)] + | ObjC_Meth_decl_info (_, class_name) -> + let class_type = Ast_expressions.create_class_type class_name in + [(CFrontend_config.self, class_type, None)] | _ -> [] else [] @@ -61,9 +65,7 @@ let get_parameters function_method_decl_info = match par with | Clang_ast_t.ParmVarDecl (decl_info, name_info, qtype, var_decl_info) -> let name = name_info.Clang_ast_t.ni_name in - Printing.log_out "Adding param '%s' " name; - Printing.log_out "with pointer %s@." decl_info.Clang_ast_t.di_pointer; - (name, CTypes.get_type qtype, var_decl_info.Clang_ast_t.vdi_init_expr) + (name, qtype, var_decl_info.Clang_ast_t.vdi_init_expr) | _ -> assert false in let pars = list_map par_to_ms_par (get_param_decls function_method_decl_info) in @@ -73,10 +75,9 @@ let get_return_type function_method_decl_info = match function_method_decl_info with | Func_decl_info (_, typ) | Cpp_Meth_decl_info (_, _, typ) - | Block_decl_info (_, typ) -> typ - | ObjC_Meth_decl_info (method_decl_info, _) -> - let qt = method_decl_info.Clang_ast_t.omdi_result_type in - CTypes.get_type qt + | Block_decl_info (_, typ) -> + Ast_expressions.create_qual_type_with_just_pointer (CTypes.return_type_of_function_type typ) + | ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_result_type let build_method_signature decl_info procname function_method_decl_info is_instance is_anonym_block is_generated = let source_range = decl_info.Clang_ast_t.di_source_range in @@ -91,7 +92,7 @@ let method_signature_of_decl class_name_opt meth_decl block_data_opt = match meth_decl, block_data_opt, class_name_opt with | FunctionDecl (decl_info, name_info, qt, fdi), _, _ -> let name = name_info.ni_name in - let func_decl = Func_decl_info (fdi, CTypes.get_type qt) in + let func_decl = Func_decl_info (fdi, qt) in let procname = General_utils.mk_procname_from_function name (CTypes.get_type qt) in let ms = build_method_signature decl_info procname func_decl false false false in ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters @@ -99,7 +100,7 @@ let method_signature_of_decl class_name_opt meth_decl block_data_opt = let method_name = name_info.Clang_ast_t.ni_name in let typ = CTypes.get_type qt in let procname = General_utils.mk_procname_from_cpp_method class_name method_name typ in - let method_decl = Cpp_Meth_decl_info (fdi, class_name, typ) in + let method_decl = Cpp_Meth_decl_info (fdi, class_name, qt) in let ms = build_method_signature decl_info procname method_decl false false false in ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters | ObjCMethodDecl (decl_info, name_info, mdi), _, Some class_name -> @@ -113,7 +114,7 @@ let method_signature_of_decl class_name_opt meth_decl block_data_opt = ms, mdi.omdi_body, mdi.omdi_parameters | BlockDecl (decl_info, decl_list, decl_context_info, bdi), Some (qt, is_instance, procname, _, _), _ -> - let func_decl = Block_decl_info (bdi, CTypes.get_type qt) in + let func_decl = Block_decl_info (bdi, qt) in let ms = build_method_signature decl_info procname func_decl is_instance true false in ms, bdi.bdi_body, bdi.bdi_parameters | _ -> raise Invalid_declaration @@ -151,7 +152,9 @@ let get_class_selector_instance context obj_c_message_expr_info act_params = let selector = obj_c_message_expr_info.Clang_ast_t.omei_selector in let pointer = obj_c_message_expr_info.Clang_ast_t.omei_decl_pointer in match obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind with - | `Class qt -> (CTypes.get_type qt, selector, pointer, MCStatic) + | `Class qt -> + let sil_type = CTypes_decl.qual_type_to_sil_type context.CContext.tenv qt in + ((CTypes.classname_of_type sil_type), selector, pointer, MCStatic) | `Instance -> (match act_params with | (instance_obj, Sil.Tptr(t, _)):: _ @@ -173,7 +176,7 @@ let get_formal_parameters tenv ms = let qt = if (name = CFrontend_config.self && CMethod_signature.ms_is_instance ms) then (Ast_expressions.create_pointer_type raw_type) - else Ast_expressions.create_qual_type raw_type in + else raw_type in let typ = CTypes_decl.qual_type_to_sil_type tenv qt in (name, typ):: defined_parameters pl' in defined_parameters (CMethod_signature.ms_get_args ms) @@ -208,9 +211,8 @@ let captured_vars_from_block_info context cvl = list_flatten (f cvl) let get_return_type tenv ms = - let qt = CMethod_signature.ms_get_ret_type ms in - CTypes_decl.qual_type_to_sil_type tenv - (Ast_expressions.create_qual_type (CTypes.get_function_return_type qt)) + let return_type = CMethod_signature.ms_get_ret_type ms in + CTypes_decl.qual_type_to_sil_type tenv return_type let sil_func_attributes_of_attributes attrs = let rec do_translation acc al = match al with diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index b2edbfabc..36215e0b2 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -184,8 +184,9 @@ struct f trans_state stmt with Self.SelfClassException class_name -> let typ = CTypes_decl.type_name_to_sil_type trans_state.context.CContext.tenv class_name in + let expanded_type = CTypes.expand_structured_type trans_state.context.CContext.tenv typ in { empty_res_trans with - exps = [(Sil.Sizeof(typ, Sil.Subtype.exact), Sil.Tint Sil.IULong)] } + exps = [(Sil.Sizeof(expanded_type, Sil.Subtype.exact), Sil.Tint Sil.IULong)] } (* Execute translation of e forcing to release priority (if it's not free) and then setting it back.*) (* This is used in conditional operators where we need to force the priority to be free for the *) @@ -320,11 +321,10 @@ struct if CTrans_models.is_modeled_builtin name then ("infer" ^ name) else name in let qt = CTypes.get_raw_qual_type_decl_ref_exp_info decl_ref_expr_info in - let pname, type_opt = + let pname = match qt with - | Some v -> - (General_utils.mk_procname_from_function name v, CTypes_decl.parse_func_type name v) - | None -> (Procname.from_string_c_fun name, None) in + | Some v -> General_utils.mk_procname_from_function name v + | None -> Procname.from_string_c_fun name in CMethod_trans.create_procdesc_with_pointer context (Some pointer) pname; let address_of_function = not context.CContext.is_callee_expression in (* If we are not translating a callee expression, then the address of the function is being taken.*) @@ -1541,7 +1541,7 @@ struct "WARNING: in MemberExpr we expect the translation of the stmt to return an expression\n" in let class_typ = (match class_typ with - | Sil.Tptr (t, _) -> CTypes_decl.expand_structured_type trans_state.context.CContext.tenv t + | Sil.Tptr (t, _) -> CTypes.expand_structured_type trans_state.context.CContext.tenv t | t -> t) in match decl_ref.Clang_ast_t.dr_kind with | `Field | `ObjCIvar -> @@ -1552,7 +1552,12 @@ struct let tenv = trans_state.context.CContext.tenv in (match ObjcInterface_decl.find_field tenv field_name (Some class_typ) false with | Some (fn, _, _) -> Sil.Lfield (obj_sil, fn, class_typ) - | None -> assert false) in + | None -> + let class_name = CTypes.classname_of_type class_typ in + let default_name = (General_utils.mk_class_field_name class_name field_name) in + Printing.log_out "Warning: Field not found %s in class %s " field_name + (Sil.typ_to_string class_typ); + Sil.Lfield (obj_sil, default_name, class_typ)) in { result_trans_exp_stmt with exps = [(exp, field_typ)] } | `CXXMethod -> @@ -1685,7 +1690,7 @@ struct and objCStringLiteral_trans trans_state stmt_info stmts info = let stmts = [Ast_expressions.create_implicit_cast_expr stmt_info stmts - (Ast_expressions.create_char_type ()) `ArrayToPointerDecay] in + Ast_expressions.create_char_star_type `ArrayToPointerDecay] in let typ = CTypes_decl.class_from_pointer_type trans_state.context.CContext.tenv info.Clang_ast_t.ei_qual_type in let obj_c_message_expr_info = Ast_expressions.make_obj_c_message_expr_info_class CFrontend_config.string_with_utf8_m typ in diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index 447b0b3e7..2f37ee057 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -135,14 +135,15 @@ let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname = let condition = class_name = CFrontend_config.nsstring_cl && method_name = CFrontend_config.string_with_utf8_m in + let id_type = Ast_expressions.create_id_type in get_predefined_ms_method condition class_name method_name Procname.Class_objc_method - mk_procname [("x", "char *", None)] CFrontend_config.id_cl [] None + mk_procname [("x", Ast_expressions.create_char_star_type, None)] id_type [] None let get_predefined_ms_retain_release class_name method_name mk_procname = let condition = is_retain_or_release method_name in let return_type = if is_retain_method method_name || is_autorelease_method method_name - then CFrontend_config.id_cl else CFrontend_config.void in + then Ast_expressions.create_id_type else Ast_expressions.create_void_type in get_predefined_ms_method condition CFrontend_config.nsobject_cl method_name Procname.Instance_objc_method mk_procname [(CFrontend_config.self, class_name, None)] return_type [] (get_builtinname method_name) @@ -150,22 +151,25 @@ let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname = let condition = method_name = CFrontend_config.init && class_name = CFrontend_config.nsautorelease_pool_cl in + let class_type = Ast_expressions.create_class_type class_name in get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method - mk_procname [(CFrontend_config.self, class_name, None)] CFrontend_config.void [] None + mk_procname [(CFrontend_config.self, class_type, None)] Ast_expressions.create_void_type [] None let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname = let condition = (method_name = CFrontend_config.release || method_name = CFrontend_config.drain) && class_name = CFrontend_config.nsautorelease_pool_cl in + let class_type = Ast_expressions.create_class_type class_name in get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method - mk_procname [(CFrontend_config.self, class_name, None)] - CFrontend_config.void [] (Some SymExec.ModelBuiltins.__objc_release_autorelease_pool) + mk_procname [(CFrontend_config.self, class_type, None)] + Ast_expressions.create_void_type [] (Some SymExec.ModelBuiltins.__objc_release_autorelease_pool) let get_predefined_model_method_signature class_name method_name mk_procname = match get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname with | Some ms -> Some ms | None -> - match get_predefined_ms_retain_release class_name method_name mk_procname with + let class_type = Ast_expressions.create_class_type class_name in + match get_predefined_ms_retain_release class_type method_name mk_procname with | Some ms -> Some ms | None -> match get_predefined_ms_stringWithUTF8String class_name method_name mk_procname with diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 3613d86a7..b19c553f3 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -278,8 +278,9 @@ let create_alloc_instrs context sil_loc function_type fname = | Sil.Tptr (styp, Sil.Pk_objc_weak) | Sil.Tptr (styp, Sil.Pk_objc_unsafe_unretained) | Sil.Tptr (styp, Sil.Pk_objc_autoreleasing) -> - function_type, CTypes_decl.expand_structured_type context.CContext.tenv styp + function_type, styp | _ -> Sil.Tptr (function_type, Sil.Pk_pointer), function_type in + let function_type_np = CTypes.expand_structured_type context.CContext.tenv function_type_np in let sizeof_exp = Sil.Sizeof (function_type_np, Sil.Subtype.exact) in let exp = (sizeof_exp, Sil.Tint Sil.IULong) in let ret_id = Ident.create_fresh Ident.knormal in @@ -333,8 +334,8 @@ let cpp_new_trans trans_state sil_loc stmt_info function_type = let create_cast_instrs context exp cast_from_typ cast_to_typ sil_loc = let ret_id = Ident.create_fresh Ident.knormal in - let cast_typ_no_pointer = - CTypes_decl.expand_structured_type context.CContext.tenv (CTypes.remove_pointer_to_typ cast_to_typ) in + let typ = CTypes.remove_pointer_to_typ cast_to_typ in + let cast_typ_no_pointer = CTypes.expand_structured_type context.CContext.tenv typ in let sizeof_exp = Sil.Sizeof (cast_typ_no_pointer, Sil.Subtype.exact) in let pname = SymExec.ModelBuiltins.__objc_cast in let args = [(exp, cast_from_typ); (sizeof_exp, Sil.Tint Sil.IULong)] in diff --git a/infer/src/clang/cTypes.ml b/infer/src/clang/cTypes.ml index 051c34d77..a134cb044 100644 --- a/infer/src/clang/cTypes.ml +++ b/infer/src/clang/cTypes.ml @@ -13,20 +13,6 @@ open Utils open CFrontend_utils module L = Logging -let get_function_return_type s = - let regexp = Str.regexp_string " (" in - let matches = try let _ = Str.search_forward regexp s 0 in true with Not_found -> false in - let regexp' = - if matches then regexp - else Str.regexp_string "(" in (* match e.g. "char *()" *) - let buf = Str.split regexp' s in - match buf with - | ret:: _ -> - let ret'= String.trim ret in - Printing.log_out "return type ='%s'@." ret'; - ret' - | _ -> assert false - let get_type qt = match qt.Clang_ast_t.qt_desugared with | Some t -> t diff --git a/infer/src/clang/cTypes.mli b/infer/src/clang/cTypes.mli index fdea7c2d6..e42544e3b 100644 --- a/infer/src/clang/cTypes.mli +++ b/infer/src/clang/cTypes.mli @@ -23,8 +23,6 @@ val search_enum_type_by_name : Sil.tenv -> string -> Sil.const option val classname_of_type : Sil.typ -> string -val get_function_return_type : string -> string - val mk_classname : string -> Sil.typename val mk_structname : string -> Sil.typename diff --git a/infer/src/clang/cTypes_decl.ml b/infer/src/clang/cTypes_decl.ml index 8306d0878..2aa73e6e4 100644 --- a/infer/src/clang/cTypes_decl.ml +++ b/infer/src/clang/cTypes_decl.ml @@ -15,26 +15,57 @@ open CFrontend_utils module L = Logging exception Typename_not_found -(* Adds the predefined types objc_class which is a struct, and Class, *) -(* which is a pointer to objc_class. *) -let add_predefined_types tenv = +let add_predefined_objc_types tenv = let objc_class_mangled = Mangled.from_string CFrontend_config.objc_class in let objc_class_name = Sil.TN_csu (Sil.Class, objc_class_mangled) in let objc_class_type_info = Sil.Tstruct ([], [], Sil.Struct, Some (Mangled.from_string CFrontend_config.objc_class), [], [], []) in Sil.tenv_add tenv objc_class_name objc_class_type_info; - let mn = Mangled.from_string CFrontend_config.class_type in - let class_typename = Sil.TN_typedef(mn) in - let class_typ = Sil.Tptr ((Sil.Tvar - (Sil.TN_csu (Sil.Struct, objc_class_mangled))), Sil.Pk_pointer) in + let class_typename = CType_to_sil_type.get_builtin_objc_typename `ObjCClass in + let class_typ = Sil.Tvar (Sil.TN_csu (Sil.Struct, objc_class_mangled)) in Sil.tenv_add tenv class_typename class_typ; let typename_objc_object = Sil.TN_csu (Sil.Struct, Mangled.from_string CFrontend_config.objc_object) in - let id_typedef = Sil.Tptr (Sil.Tvar (typename_objc_object), Sil.Pk_pointer) in - let id_typename = Sil.TN_typedef (Mangled.from_string CFrontend_config.id_cl) in + let id_typedef = Sil.Tvar (typename_objc_object) in + let id_typename = CType_to_sil_type.get_builtin_objc_typename `ObjCId in Sil.tenv_add tenv id_typename id_typedef +(* Whenever new type are added manually to the translation in ast_expressions, *) +(* they should be added here too!! *) +let add_predefined_basic_types tenv = + let open Ast_expressions in + let open Clang_ast_t in + let add_basic_type qt basic_type_kind = + let sil_type = CType_to_sil_type.sil_type_of_builtin_type_kind basic_type_kind in + Ast_utils.update_sil_types_map qt.Clang_ast_t.qt_type_ptr sil_type in + let add_pointer_type qt sil_type = + let pointer_type = CTypes.add_pointer_to_typ sil_type in + Ast_utils.update_sil_types_map qt.Clang_ast_t.qt_type_ptr pointer_type in + let add_function_type qt return_type = + (* We translate function types as the return type of the function *) + Ast_utils.update_sil_types_map qt.Clang_ast_t.qt_type_ptr return_type in + let sil_void_type = CType_to_sil_type.sil_type_of_builtin_type_kind `Void in + let sil_char_type = CType_to_sil_type.sil_type_of_builtin_type_kind `Char_S in + let sil_nsarray_type = Sil.Tvar (CTypes.mk_classname CFrontend_config.nsarray_cl) in + let sil_id_type = CType_to_sil_type.get_builtin_objc_type `ObjCId in + add_basic_type create_int_type `Int; + add_basic_type create_void_type `Void; + add_basic_type create_char_star_type `Char_S; + add_basic_type create_BOOL_type `SChar; + add_basic_type create_unsigned_long_type `ULong; + add_pointer_type create_void_star_type sil_void_type; + add_pointer_type create_char_star_type sil_char_type; + add_pointer_type create_char_star_type sil_char_type; + add_pointer_type create_nsarray_star_type sil_nsarray_type; + add_pointer_type create_id_type sil_id_type; + add_function_type create_void_unsigned_long_type sil_void_type; + add_function_type create_void_void_type sil_void_type + +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 diff --git a/infer/src/clang/objcProperty_decl.ml b/infer/src/clang/objcProperty_decl.ml index 978f33e70..c516240ae 100644 --- a/infer/src/clang/objcProperty_decl.ml +++ b/infer/src/clang/objcProperty_decl.ml @@ -270,8 +270,9 @@ let make_getter curr_class prop_name prop_type = match getter with | Some (ObjCMethodDecl(di, name_info, mdi), _) -> let dummy_info = Ast_expressions.dummy_decl_info_in_curr_file di in + let class_name = CContext.get_curr_class_name curr_class in let deref_self_field = Ast_expressions.make_deref_self_field - (CContext.get_qt_curr_class curr_class) dummy_info mdi.Clang_ast_t.omdi_result_type ivar_name in + class_name dummy_info mdi.Clang_ast_t.omdi_result_type ivar_name in let body = ReturnStmt(Ast_expressions.make_stmt_info dummy_info, [deref_self_field]) in let mdi'= Ast_expressions.make_method_decl_info mdi body in let generated_name_info = create_generated_method_name name_info in @@ -302,7 +303,7 @@ let make_setter curr_class prop_name prop_type = let stmt_info = Ast_expressions.make_stmt_info dummy_info in let rhs_exp = Ast_expressions.make_cast_expr qt_param di decl_ref_expr_info' `ObjCProperty in let lhs_exp = Ast_expressions.make_self_field - (CContext.get_qt_curr_class curr_class) di qt_param ivar_name in + (CContext.get_curr_class_name curr_class) di qt_param ivar_name in let boi = { Clang_ast_t.boi_kind = `Assign } in let setter = Ast_expressions.make_binary_stmt lhs_exp rhs_exp stmt_info expr_info boi in let memory_management_attribute = (get_memory_management_attribute attributes) in