From e49d9d6f4df26e748f6c3087c978bd5a7ea6106a Mon Sep 17 00:00:00 2001 From: Dulma Rodriguez Date: Mon, 12 Oct 2015 06:18:34 -0700 Subject: [PATCH] Adding an outer context to the context in case of blocks Reviewed By: @ddino Differential Revision: D2526315 fb-gh-sync-id: 89a6d3f --- infer/src/clang/cContext.ml | 59 ++++++++++++++++++++++---------- infer/src/clang/cContext.mli | 11 ++++-- infer/src/clang/cEnum_decl.ml | 2 +- infer/src/clang/cMethod_decl.ml | 29 +++++++--------- infer/src/clang/cMethod_trans.ml | 9 +++-- infer/src/clang/cTrans.ml | 6 ++-- 6 files changed, 70 insertions(+), 46 deletions(-) diff --git a/infer/src/clang/cContext.ml b/infer/src/clang/cContext.ml index f35766a66..29098a939 100644 --- a/infer/src/clang/cContext.ml +++ b/infer/src/clang/cContext.ml @@ -35,14 +35,15 @@ type t = cfg : Cfg.cfg; procdesc : Cfg.Procdesc.t; is_objc_method : bool; - is_instance : bool; curr_class: curr_class; is_callee_expression : bool; namespace: string option; (* contains the name of the namespace if we are in the scope of one*) mutable local_vars : (Mangled.t * Sil.typ * bool) list; (* (name, type, is_static flag) *) mutable captured_vars : (Mangled.t * Sil.typ * bool) list; (* (name, type, is_static flag) *) mutable local_vars_stack : varMap; - mutable local_vars_pointer : pointerVarMap + mutable local_vars_pointer : pointerVarMap; + outer_context : t option; (* in case of objc blocks, the context of the method containing the block *) + mutable blocks : Procname.t list (* List of blocks defined in this method *) } module LocalVars = @@ -141,17 +142,17 @@ struct try Some (fst (lookup_var_locals context procname var_name)) with Stack.Empty -> - try - Some (fst (lookup_var_globals context procname var_name)) - with Not_found -> - if is_captured_var context var_name then - try (* if it's a captured variable we need to look at the parameters list*) - Some (fst (lookup_var_formals context procname var_name)) - with Not_found -> - Printing.log_err "Variable %s not found!!\n%!" var_name; - print_locals context; - None - else None + try + Some (fst (lookup_var_globals context procname var_name)) + with Not_found -> + if is_captured_var context var_name then + try (* if it's a captured variable we need to look at the parameters list*) + Some (fst (lookup_var_formals context procname var_name)) + with Not_found -> + Printing.log_err "Variable %s not found!!\n%!" var_name; + print_locals context; + None + else None else if (kind = `ParmVar) then try Some (fst (lookup_var_formals context procname var_name)) @@ -217,7 +218,7 @@ struct end -let create_context tenv cg cfg procdesc ns curr_class is_objc_method cv is_instance = +let create_context tenv cg cfg procdesc ns curr_class is_objc_method cv outer_context_opt = { tenv = tenv; cg = cg; cfg = cfg; @@ -225,12 +226,13 @@ let create_context tenv cg cfg procdesc ns curr_class is_objc_method cv is_insta curr_class = curr_class; is_callee_expression = false; is_objc_method = is_objc_method; - is_instance = is_instance; namespace = ns; local_vars = []; captured_vars = cv; local_vars_stack = StringMap.empty; - local_vars_pointer = StringMap.empty + local_vars_pointer = StringMap.empty; + outer_context = outer_context_opt; + blocks = [] } let get_cfg context = context.cfg @@ -241,9 +243,24 @@ let get_tenv context = context.tenv let get_procdesc context = context.procdesc -let is_objc_method context = context.is_objc_method +let rec is_objc_method context = + match context.outer_context with + | Some outer_context -> is_objc_method outer_context + | None -> context.is_objc_method + +let rec is_objc_instance context = + match context.outer_context with + | Some outer_context -> is_objc_instance outer_context + | None -> + let attrs = Cfg.Procdesc.get_attributes context.procdesc in + attrs.ProcAttributes.is_objc_instance_method + +let rec get_curr_class context = + match context.curr_class, context.outer_context with + | ContextNoCls, Some outer_context -> + get_curr_class outer_context + | _ -> context.curr_class -let get_curr_class context = context.curr_class let get_curr_class_name curr_class = match curr_class with @@ -299,3 +316,9 @@ let create_curr_class tenv class_name = ContextCls (class_name, Some superclass, protocols) | [] -> ContextCls (class_name, None, [])) | _ -> assert false + +let rec add_block context block = + context.blocks <- block :: context.blocks; + match context.outer_context with + | Some outer_context -> add_block outer_context block + | None -> () diff --git a/infer/src/clang/cContext.mli b/infer/src/clang/cContext.mli index 555d410fd..e7ca8cd09 100644 --- a/infer/src/clang/cContext.mli +++ b/infer/src/clang/cContext.mli @@ -27,14 +27,15 @@ type t = cfg : Cfg.cfg; procdesc : Cfg.Procdesc.t; is_objc_method : bool; - is_instance : bool; curr_class: curr_class; is_callee_expression : bool; namespace: string option; (* contains the name of the namespace if we are in the scope of one*) mutable local_vars : (Mangled.t * Sil.typ * bool) list; (* (name, type, is_static flag) *) mutable captured_vars : (Mangled.t * Sil.typ * bool) list; (* (name, type, is_static flag) *) mutable local_vars_stack : varMap; - mutable local_vars_pointer : pointerVarMap + mutable local_vars_pointer : pointerVarMap; + outer_context : t option; (* in case of objc blocks, the context of the method containing the block *) + mutable blocks : Procname.t list (* List of blocks defined in this method *) } module LocalVars : @@ -71,6 +72,10 @@ val is_objc_method : t -> bool val get_tenv : t -> Sil.tenv val create_context : Sil.tenv -> Cg.t -> Cfg.cfg -> Cfg.Procdesc.t -> - string option -> curr_class -> bool -> (Mangled.t * Sil.typ * bool) list -> bool -> t + string option -> curr_class -> bool -> (Mangled.t * Sil.typ * bool) list -> t option -> t val create_curr_class : Sil.tenv -> string -> curr_class + +val add_block : t -> Procname.t -> unit + +val is_objc_instance : t -> bool diff --git a/infer/src/clang/cEnum_decl.ml b/infer/src/clang/cEnum_decl.ml index 263bd0b1f..43fcf6a91 100644 --- a/infer/src/clang/cEnum_decl.ml +++ b/infer/src/clang/cEnum_decl.ml @@ -51,7 +51,7 @@ let enum_decl name tenv cfg cg namespace type_ptr decl_list opt_type = Printing.log_out "ADDING: EnumDecl '%s'\n" name; let context' = CContext.create_context tenv cg cfg !global_procdesc namespace CContext.ContextNoCls - false [] false in + false [] None in let enum_constants = get_enum_constants context' decl_list 0 in let name = (match opt_type with (* If the type is defined it's of the kind "enum name" and we take that.*) | `Type s -> s diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index 7fb2a77e7..ea62d7af8 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -38,8 +38,9 @@ struct Specs.summary_exists_in_models procname && not !CFrontend_config.models_mode (* Translates the method/function's body into nodes of the cfg. *) - let add_method tenv cg cfg class_decl_opt procname namespace instrs is_objc_method is_instance - captured_vars is_anonym_block extra_instrs = + let add_method tenv cg cfg class_decl_opt procname namespace instrs is_objc_method + captured_vars outer_context_opt extra_instrs = + Printing.log_out "\n\n>>---------- ADDING METHOD: '%s' ---------<<\n@." (Procname.to_string procname); try @@ -48,7 +49,7 @@ struct if (Cfg.Procdesc.is_defined procdesc && not (model_exists procname)) then (let context = CContext.create_context tenv cg cfg procdesc namespace class_decl_opt - is_objc_method captured_vars is_instance in + is_objc_method captured_vars outer_context_opt in CVar_decl.get_fun_locals context instrs; let local_vars = list_map (fun (n, t, _) -> n, t) context.CContext.local_vars in let start_node = Cfg.Procdesc.get_start_node procdesc in @@ -59,6 +60,7 @@ struct "\n\n>>---------- Start translating body of function: '%s' ---------<<\n@." (Procname.to_string procname); let meth_body_nodes = T.instructions_trans context instrs extra_instrs exit_node in + let is_anonym_block = Option.is_some outer_context_opt in if (not is_anonym_block) then CContext.LocalVars.reset_block (); Cfg.Node.set_succs_exn start_node meth_body_nodes []; Cg.add_node (CContext.get_cg context) (Cfg.Procdesc.get_proc_name procdesc)) @@ -77,24 +79,18 @@ struct let function_decl tenv cfg cg namespace func_decl block_data_opt = Printing.log_out "\nResetting the goto_labels hashmap...\n"; CTrans_utils.GotoLabel.reset_all_labels (); (* C Language Std 6.8.6.1-1 *) - let is_anonym_block, captured_vars, curr_class = + let captured_vars, outer_context_opt = match block_data_opt with - | Some (context, _, _, captured_vars) -> - let curr_class = context.CContext.curr_class in - true, captured_vars, curr_class - | None -> false, [], CContext.ContextNoCls in - let class_name = - if curr_class = CContext.ContextNoCls then None else Some (CContext.get_curr_class_name curr_class) in + | Some (outer_context, _, _, captured_vars) -> captured_vars, Some outer_context + | None -> [], None in let ms, body_opt, extra_instrs = - CMethod_trans.method_signature_of_decl class_name func_decl block_data_opt in + CMethod_trans.method_signature_of_decl None func_decl block_data_opt in match method_body_to_translate ms body_opt with | Some body -> (* Only in the case the function declaration has a defined body we create a procdesc *) let procname = CMethod_signature.ms_get_name ms in if CMethod_trans.create_local_procdesc cfg tenv ms [body] captured_vars false then - let is_instance = CMethod_signature.ms_is_instance ms in - let is_objc_method = is_anonym_block in - add_method tenv cg cfg curr_class procname namespace [body] is_objc_method is_instance - captured_vars is_anonym_block extra_instrs + add_method tenv cg cfg CContext.ContextNoCls procname namespace [body] false + captured_vars outer_context_opt extra_instrs | None -> () let process_method_decl tenv cg cfg namespace curr_class meth_decl ~is_objc = @@ -106,8 +102,7 @@ struct let is_instance = CMethod_signature.ms_is_instance ms in let procname = CMethod_signature.ms_get_name ms in if CMethod_trans.create_local_procdesc cfg tenv ms [body] [] is_instance then - add_method tenv cg cfg curr_class procname namespace [body] is_objc is_instance [] false - extra_instrs + add_method tenv cg cfg curr_class procname namespace [body] is_objc [] None extra_instrs | None -> () let rec process_one_method_decl tenv cg cfg curr_class namespace dec = diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index f426327a3..768da037f 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -35,11 +35,10 @@ type function_method_decl_info = let is_instance_method function_method_decl_info = match function_method_decl_info with - | Func_decl_info (function_decl_info, _, _) -> false + | Func_decl_info _ | Block_decl_info _ -> false | Cpp_Meth_decl_info _ -> true | ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_is_instance_method - | Block_decl_info (_, _, context) -> context.CContext.is_instance let get_class_param function_method_decl_info = if (is_instance_method function_method_decl_info) then @@ -135,8 +134,8 @@ let method_signature_of_decl class_name_opt meth_decl block_data_opt = let extra_instrs = get_assume_not_null_calls ms mdi.omdi_parameters in ms, mdi.omdi_body, extra_instrs | BlockDecl (decl_info, decl_list, decl_context_info, bdi), - Some (context, tp, procname, _), _ -> - let func_decl = Block_decl_info (bdi, tp, context) in + Some (outer_context, tp, procname, _), _ -> + let func_decl = Block_decl_info (bdi, tp, outer_context) in let ms = build_method_signature decl_info procname func_decl true false in let extra_instrs = get_assume_not_null_calls ms bdi.bdi_parameters in ms, bdi.bdi_body, extra_instrs @@ -228,7 +227,7 @@ let captured_vars_from_block_info context cvl = (match dr.Clang_ast_t.dr_name, dr.Clang_ast_t.dr_type_ptr with | Some name_info, _ -> let n = name_info.Clang_ast_t.ni_name in - if n = CFrontend_config.self && not context.CContext.is_instance then [] + if n = CFrontend_config.self && not (CContext.is_objc_instance context) then [] else (let procdesc_formals = Cfg.Procdesc.get_formals context.CContext.procdesc in (Printing.log_err "formals are %s@." (Utils.list_to_string (fun (x, _) -> x) procdesc_formals)); diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index ed83ef264..9ec5b59f1 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -348,11 +348,12 @@ struct let e = Sil.Lvar pvar in let exps = if Self.is_var_self pvar (CContext.is_objc_method context) then + let curr_class = CContext.get_curr_class context in if (CTypes.is_class typ) then - raise (Self.SelfClassException (CContext.get_curr_class_name trans_state.context.curr_class)) + raise (Self.SelfClassException (CContext.get_curr_class_name curr_class)) else let typ = CTypes.add_pointer_to_typ - (CTypes_decl.get_type_curr_class context.tenv (CContext.get_curr_class context)) in + (CTypes_decl.get_type_curr_class context.tenv curr_class) in [(e, typ)] else [(e, typ)] in Printing.log_out "\n\n PVAR ='%s'\n\n" (Sil.pvar_to_string pvar); @@ -1769,6 +1770,7 @@ struct let ids_instrs = list_map assign_captured_var all_captured_vars in let ids, instrs = list_split ids_instrs in let block_data = (context, type_ptr, block_pname, all_captured_vars) in + CContext.add_block context block_pname; M.function_decl context.tenv context.cfg context.cg context.namespace decl (Some block_data); Cfg.set_procname_priority context.cfg block_pname; let captured_exps = list_map (fun id -> Sil.Var id) ids in