diff --git a/infer/src/IR/Ident.ml b/infer/src/IR/Ident.ml index a269933ca..b8fd2a0e7 100644 --- a/infer/src/IR/Ident.ml +++ b/infer/src/IR/Ident.ml @@ -156,9 +156,6 @@ end (** Name used for the return variable *) let name_return = Mangled.from_string "return" -(** Name used for the return param variable *) -let name_return_param = Mangled.from_string "__return_param" - (** Return the standard name for the given kind *) let standard_name kind = if equal_kind kind KNormal || equal_kind kind KNone then Name.Normal diff --git a/infer/src/IR/Ident.mli b/infer/src/IR/Ident.mli index f11093b03..775c8ea88 100644 --- a/infer/src/IR/Ident.mli +++ b/infer/src/IR/Ident.mli @@ -69,9 +69,6 @@ val name_spec : name val name_return : Mangled.t (** Name used for the return variable *) -val name_return_param : Mangled.t -(** Name used for the return param variable *) - val string_to_name : string -> name (** Convert a string to a name. *) diff --git a/infer/src/IR/Mangled.ml b/infer/src/IR/Mangled.ml index c4e365a36..09945de5d 100644 --- a/infer/src/IR/Mangled.ml +++ b/infer/src/IR/Mangled.ml @@ -42,6 +42,10 @@ let self = from_string "self" let is_self = function {plain= "self"} -> true | _ -> false +let return_param = from_string "__return_param" + +let is_return_param = function {plain= "__return_param"} -> true | _ -> false + module Set = PrettyPrintable.MakePPSet (struct type nonrec t = t [@@deriving compare] diff --git a/infer/src/IR/Mangled.mli b/infer/src/IR/Mangled.mli index e582998c8..dba220e28 100644 --- a/infer/src/IR/Mangled.mli +++ b/infer/src/IR/Mangled.mli @@ -39,6 +39,10 @@ val self : t [@@warning "-32"] val is_self : t -> bool +val return_param : t + +val is_return_param : t -> bool + (** Set of Mangled. *) module Set : PrettyPrintable.PPSet with type elt = t diff --git a/infer/src/IR/Pvar.ml b/infer/src/IR/Pvar.ml index 02001f5f9..2412da5e4 100644 --- a/infer/src/IR/Pvar.ml +++ b/infer/src/IR/Pvar.ml @@ -236,7 +236,7 @@ let mk (name : Mangled.t) (proc_name : Procname.t) : t = let get_ret_pvar pname = mk Ident.name_return pname -let get_ret_param_pvar pname = mk Ident.name_return_param pname +let get_ret_param_pvar pname = mk Mangled.return_param pname (** [mk_callee name proc_name] creates a program var for a callee function with the given function name *) diff --git a/infer/src/clang/CAddImplicitGettersSetters.ml b/infer/src/clang/CAddImplicitGettersSetters.ml index 4c8adf187..d23a20410 100644 --- a/infer/src/clang/CAddImplicitGettersSetters.ml +++ b/infer/src/clang/CAddImplicitGettersSetters.ml @@ -7,39 +7,47 @@ open! IStd -let objc_getter proc_desc location (self_var, self_typ) (fieldname, field_typ, _) = - let id_pvar = Ident.create_fresh Ident.knormal in - let load_pvar_instr = - Sil.Load {id= id_pvar; e= Lvar self_var; root_typ= self_typ; typ= self_typ; loc= location} - in - let id_field = Ident.create_fresh Ident.knormal in - let class_typ = match self_typ.Typ.desc with Typ.Tptr (t, _) -> t | _ -> self_typ in - let e = Exp.Lfield (Var id_pvar, fieldname, class_typ) in - let load_field_instr = - Sil.Load {id= id_field; e; root_typ= field_typ; typ= field_typ; loc= location} - in - let exp_var = Exp.Lvar (Procdesc.get_ret_var proc_desc) in - let return_exp = - Sil.Store {e1= exp_var; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location} - in - [load_pvar_instr; load_field_instr; return_exp] - - -let objc_setter location (self, self_typ) (var, var_typ) (fieldname, field_typ, _) = +let get_load_self_instr location (self, self_typ) fieldname = let id_self = Ident.create_fresh Ident.knormal in let load_self_instr = Sil.Load {id= id_self; e= Lvar self; root_typ= self_typ; typ= self_typ; loc= location} in - let id_var = Ident.create_fresh Ident.knormal in - let load_var_instr = - Sil.Load {id= id_var; e= Lvar var; root_typ= var_typ; typ= var_typ; loc= location} - in let class_typ = match self_typ.Typ.desc with Typ.Tptr (t, _) -> t | _ -> self_typ in let field_exp = Exp.Lfield (Var id_self, fieldname, class_typ) in - let store_exp = - Sil.Store {e1= field_exp; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_var; loc= location} + (field_exp, load_self_instr) + + +let objc_getter proc_desc location self_with_typ (fieldname, field_typ, _) = + let field_exp, load_self_instr = get_load_self_instr location self_with_typ fieldname in + let store_instrs = + let id_field = Ident.create_fresh Ident.knormal in + let load_field_instr = + Sil.Load {id= id_field; e= field_exp; root_typ= field_typ; typ= field_typ; loc= location} + in + let exp_var = Exp.Lvar (Procdesc.get_ret_var proc_desc) in + let return_exp = + Sil.Store + {e1= exp_var; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location} + in + [load_field_instr; return_exp] + in + load_self_instr :: store_instrs + + +let objc_setter location self_with_typ (var, var_typ) (fieldname, field_typ, _) = + let field_exp, load_self_instr = get_load_self_instr location self_with_typ fieldname in + let store_instrs = + let id_field = Ident.create_fresh Ident.knormal in + let load_var_instr = + Sil.Load {id= id_field; e= Lvar var; root_typ= var_typ; typ= var_typ; loc= location} + in + let store_exp = + Sil.Store + {e1= field_exp; root_typ= field_typ; typ= field_typ; e2= Exp.Var id_field; loc= location} + in + [load_var_instr; store_exp] in - [load_self_instr; load_var_instr; store_exp] + load_self_instr :: store_instrs let process_getter_setter proc_name proc_desc = diff --git a/infer/src/clang/CStructUtils.ml b/infer/src/clang/CStructUtils.ml new file mode 100644 index 000000000..f9878544e --- /dev/null +++ b/infer/src/clang/CStructUtils.ml @@ -0,0 +1,26 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd + +let struct_copy tenv loc e1 e2 ~typ ~struct_name = + let rec struct_copy_helper e1 e2 typ struct_name rev_acc = + let {Struct.fields} = Option.value_exn (Tenv.lookup tenv struct_name) in + List.fold fields ~init:rev_acc ~f:(fun rev_acc (field_name, field_typ, _) -> + let mk_field e = Exp.Lfield (e, field_name, typ) in + let e1 = mk_field e1 in + let e2 = mk_field e2 in + match field_typ.Typ.desc with + | Tstruct (CStruct _ as struct_name) -> + struct_copy_helper e1 e2 field_typ struct_name rev_acc + | _ -> + let id = Ident.create_fresh Ident.knormal in + Sil.Store {e1; root_typ= field_typ; typ= field_typ; e2= Exp.Var id; loc} + :: Sil.Load {id; e= e2; root_typ= field_typ; typ= field_typ; loc} + :: rev_acc ) + in + if Exp.equal e1 e2 then [] else struct_copy_helper e1 e2 typ struct_name [] |> List.rev diff --git a/infer/src/clang/CStructUtils.mli b/infer/src/clang/CStructUtils.mli new file mode 100644 index 000000000..b5a04a950 --- /dev/null +++ b/infer/src/clang/CStructUtils.mli @@ -0,0 +1,11 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd + +val struct_copy : + Tenv.t -> Location.t -> Exp.t -> Exp.t -> typ:Typ.t -> struct_name:Typ.name -> Sil.instr list diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index f7b6d2741..62f8f0838 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -986,25 +986,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s mk_trans_result (array_exp, typ) control - and struct_copy tenv loc e1 e2 typ struct_name = - let rec struct_copy_helper e1 e2 typ struct_name rev_acc = - let {Struct.fields} = Option.value_exn (Tenv.lookup tenv struct_name) in - List.fold fields ~init:rev_acc ~f:(fun rev_acc (field_name, field_typ, _) -> - let mk_field e = Exp.Lfield (e, field_name, typ) in - let e1 = mk_field e1 in - let e2 = mk_field e2 in - match field_typ.Typ.desc with - | Tstruct (CStruct _ as struct_name) -> - struct_copy_helper e1 e2 field_typ struct_name rev_acc - | _ -> - let id = Ident.create_fresh Ident.knormal in - Sil.Store {e1; root_typ= field_typ; typ= field_typ; e2= Exp.Var id; loc} - :: Sil.Load {id; e= e2; root_typ= field_typ; typ= field_typ; loc} - :: rev_acc ) - in - if Exp.equal e1 e2 then [] else struct_copy_helper e1 e2 typ struct_name [] |> List.rev - - and binaryOperator_trans trans_state binary_operator_info stmt_info expr_info stmt_list = L.debug Capture Verbose " BinaryOperator '%a' " (Pp.of_string ~f:Clang_ast_j.string_of_binary_operator_kind) @@ -1029,8 +1010,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s (instruction trans_state' s1, instruction trans_state' s2) in let instrs = - struct_copy context.CContext.tenv sil_loc (fst res_trans_e1.return) - (fst res_trans_e2.return) res_typ struct_name + CStructUtils.struct_copy context.CContext.tenv sil_loc (fst res_trans_e1.return) + (fst res_trans_e2.return) ~typ:res_typ ~struct_name in [res_trans_e1.control; res_trans_e2.control; {empty_control with instrs}] |> PriorityNode.compute_controls_to_parent trans_state_pri sil_loc node_name stmt_info @@ -2643,7 +2624,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let instrs = match cstruct_name_opt with | Some struct_name -> - struct_copy context.CContext.tenv sil_loc var_exp sil_e1' var_typ struct_name + CStructUtils.struct_copy context.CContext.tenv sil_loc var_exp sil_e1' ~typ:var_typ + ~struct_name | None -> [Sil.Store {e1= var_exp; root_typ= ie_typ; typ= ie_typ; e2= sil_e1'; loc= sil_loc}] in @@ -3033,8 +3015,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s , Some {desc= Tptr ({desc= Tstruct (CStruct _ as struct_name)}, _)} ) -> (* return (exp:struct); *) return_stmt stmt ~mk_ret_instrs:(fun ret_exp _root_typ ret_typ res_trans_stmt -> - struct_copy context.CContext.tenv sil_loc ret_exp (fst res_trans_stmt.return) ret_typ - struct_name ) + CStructUtils.struct_copy context.CContext.tenv sil_loc ret_exp + (fst res_trans_stmt.return) ~typ:ret_typ ~struct_name ) | [stmt], _ -> (* return exp; *) return_stmt stmt ~mk_ret_instrs:(fun ret_exp root_typ ret_typ res_trans_stmt -> diff --git a/infer/src/pulse/PulseObjectiveCSummary.ml b/infer/src/pulse/PulseObjectiveCSummary.ml index 4a4516395..3a3bbfa28 100644 --- a/infer/src/pulse/PulseObjectiveCSummary.ml +++ b/infer/src/pulse/PulseObjectiveCSummary.ml @@ -44,8 +44,7 @@ let mk_objc_method_nil_summary_aux tenv proc_desc astate = let* astate, self_value = PulseOperations.eval_deref location (Lvar self) astate in let* astate = PulseArithmetic.prune_eq_zero (fst self_value) astate in match List.last (Procdesc.get_formals proc_desc) with - | Some (last_formal, {desc= Tptr (typ, _)}) when Mangled.equal last_formal Ident.name_return_param - -> + | Some (last_formal, {desc= Tptr (typ, _)}) when Mangled.is_return_param last_formal -> let ret_param_var = Procdesc.get_ret_param_var proc_desc in let* astate, ret_param_var_addr_hist = PulseOperations.eval_deref location (Lvar ret_param_var) astate