diff --git a/infer/src/backend/callbacks.ml b/infer/src/backend/callbacks.ml index 51dc97054..12ee05775 100644 --- a/infer/src/backend/callbacks.ml +++ b/infer/src/backend/callbacks.ml @@ -12,78 +12,6 @@ module L = Logging (** Module to register and invoke callbacks *) -(** Inline a synthetic (access or bridge) method. *) -let inline_synthetic_method ret_ids etl proc_desc proc_name loc_call : Sil.instr option = - let modified = ref None in - let debug = false in - let found instr instr' = - modified := Some instr'; - if debug then - begin - L.stderr "XX inline_synthetic_method found instr: %a@." (Sil.pp_instr pe_text) instr; - L.stderr "XX inline_synthetic_method instr': %a@." (Sil.pp_instr pe_text) instr' - end in - let do_instr node instr = - match instr, ret_ids, etl with - | Sil.Letderef (id1, Sil.Lfield (Sil.Var id2, fn, ft), bt, loc), [ret_id], [(e1, t1)] -> (* getter for fields *) - let instr' = Sil.Letderef (ret_id, Sil.Lfield (e1, fn, ft), bt, loc_call) in - found instr instr' - | Sil.Letderef (id1, Sil.Lfield (Sil.Lvar pvar, fn, ft), bt, loc), [ret_id], [] - when Sil.pvar_is_global pvar -> (* getter for static fields *) - let instr' = Sil.Letderef (ret_id, Sil.Lfield (Sil.Lvar pvar, fn, ft), bt, loc_call) in - found instr instr' - | Sil.Set (Sil.Lfield (ex1, fn, ft), bt , ex2, loc), _, [(e1, t1); (e2, t2)] -> (* setter for fields *) - let instr' = Sil.Set (Sil.Lfield (e1, fn, ft), bt , e2, loc_call) in - found instr instr' - | Sil.Set (Sil.Lfield (Sil.Lvar pvar, fn, ft), bt , ex2, loc), _, [(e1, t1)] - when Sil.pvar_is_global pvar -> (* setter for static fields *) - let instr' = Sil.Set (Sil.Lfield (Sil.Lvar pvar, fn, ft), bt , e1, loc_call) in - found instr instr' - | Sil.Call (ret_ids', Sil.Const (Sil.Cfun pn), etl', loc', cf), _, _ - when IList.length ret_ids = IList.length ret_ids' - && IList.length etl' = IList.length etl -> - let instr' = Sil.Call (ret_ids, Sil.Const (Sil.Cfun pn), etl, loc_call, cf) in - found instr instr' - | Sil.Call (ret_ids', Sil.Const (Sil.Cfun pn), etl', loc', cf), _, _ - when IList.length ret_ids = IList.length ret_ids' - && IList.length etl' + 1 = IList.length etl -> - let etl1 = match IList.rev etl with (* remove last element *) - | _ :: l -> IList.rev l - | [] -> assert false in - let instr' = Sil.Call (ret_ids, Sil.Const (Sil.Cfun pn), etl1, loc_call, cf) in - found instr instr' - | _ -> () in - Cfg.Procdesc.iter_instrs do_instr proc_desc; - !modified - -(** Find synthetic (access or bridge) methods in the procedure and inline them in the cfg. *) -let proc_inline_synthetic_methods cfg proc_desc : unit = - let instr_inline_synthetic_method = function - | Sil.Call (ret_ids, Sil.Const (Sil.Cfun pn), etl, loc, _) -> - (match Cfg.Procdesc.find_from_name cfg pn with - | Some pd -> - let is_access = Procname.java_is_access_method pn in - let attributes = Cfg.Procdesc.get_attributes pd in - let is_synthetic = attributes.ProcAttributes.is_synthetic_method in - let is_bridge = attributes.ProcAttributes.is_bridge_method in - if is_access || is_bridge || is_synthetic - then inline_synthetic_method ret_ids etl pd pn loc - else None - | None -> None) - | _ -> None in - let node_inline_synthetic_methods node = - let modified = ref false in - let do_instr instr = match instr_inline_synthetic_method instr with - | None -> instr - | Some instr' -> - modified := true; - instr' in - let instrs = Cfg.Node.get_instrs node in - let instrs' = IList.map do_instr instrs in - if !modified then Cfg.Node.replace_instrs node instrs' in - Cfg.Procdesc.iter_nodes node_inline_synthetic_methods proc_desc - - type proc_callback_t = Procname.t list -> (Procname.t -> Cfg.Procdesc.t option) -> @@ -119,7 +47,6 @@ let get_procedure_definition exe_env proc_name = let tenv = Exe_env.get_tenv exe_env proc_name in Option.map (fun proc_desc -> - proc_inline_synthetic_methods cfg proc_desc; let idenv = Idenv.create cfg proc_desc and language = (Cfg.Procdesc.get_attributes proc_desc).ProcAttributes.language in (idenv, tenv, proc_name, proc_desc, language)) diff --git a/infer/src/backend/callbacks.mli b/infer/src/backend/callbacks.mli index f603bb4d5..e578bb9b6 100644 --- a/infer/src/backend/callbacks.mli +++ b/infer/src/backend/callbacks.mli @@ -42,6 +42,3 @@ val unregister_all_callbacks : unit -> unit (** Invoke all the registered callbacks. *) val iterate_callbacks : (Procname.t -> unit) -> Cg.t -> Exe_env.t -> unit - -(** Find synthetic (access or bridge) methods in the procedure and inline them in the cfg. *) -val proc_inline_synthetic_methods: Cfg.cfg -> Cfg.Procdesc.t -> unit diff --git a/infer/src/backend/cfg.ml b/infer/src/backend/cfg.ml index c759c4030..16f803a22 100644 --- a/infer/src/backend/cfg.ml +++ b/infer/src/backend/cfg.ml @@ -586,7 +586,7 @@ module Node = struct match get_succs node with | [n] -> if not (NodeSet.mem n !visited) - && not (equal node dst_node) + && not (equal node dst_node) then do_node n | _ -> () end in @@ -967,8 +967,91 @@ let save_attributes filename cfg = AttributesTable.store_attributes attributes' in IList.iter save_proc (get_all_procs cfg) +(** Inline a synthetic (access or bridge) method. *) +let inline_synthetic_method ret_ids etl proc_desc proc_name loc_call : Sil.instr option = + let modified = ref None in + let debug = false in + let found instr instr' = + modified := Some instr'; + if debug then + begin + L.stderr "XX inline_synthetic_method found instr: %a@." (Sil.pp_instr pe_text) instr; + L.stderr "XX inline_synthetic_method instr': %a@." (Sil.pp_instr pe_text) instr' + end in + let do_instr node instr = + match instr, ret_ids, etl with + | Sil.Letderef (id1, Sil.Lfield (Sil.Var id2, fn, ft), bt, loc), + [ret_id], + [(e1, t1)] -> (* getter for fields *) + let instr' = Sil.Letderef (ret_id, Sil.Lfield (e1, fn, ft), bt, loc_call) in + found instr instr' + | Sil.Letderef (id1, Sil.Lfield (Sil.Lvar pvar, fn, ft), bt, loc), [ret_id], [] + when Sil.pvar_is_global pvar -> (* getter for static fields *) + let instr' = Sil.Letderef (ret_id, Sil.Lfield (Sil.Lvar pvar, fn, ft), bt, loc_call) in + found instr instr' + | Sil.Set (Sil.Lfield (ex1, fn, ft), bt , ex2, loc), + _, + [(e1, t1); (e2, t2)] -> (* setter for fields *) + let instr' = Sil.Set (Sil.Lfield (e1, fn, ft), bt , e2, loc_call) in + found instr instr' + | Sil.Set (Sil.Lfield (Sil.Lvar pvar, fn, ft), bt , ex2, loc), _, [(e1, t1)] + when Sil.pvar_is_global pvar -> (* setter for static fields *) + let instr' = Sil.Set (Sil.Lfield (Sil.Lvar pvar, fn, ft), bt , e1, loc_call) in + found instr instr' + | Sil.Call (ret_ids', Sil.Const (Sil.Cfun pn), etl', loc', cf), _, _ + when IList.length ret_ids = IList.length ret_ids' + && IList.length etl' = IList.length etl -> + let instr' = Sil.Call (ret_ids, Sil.Const (Sil.Cfun pn), etl, loc_call, cf) in + found instr instr' + | Sil.Call (ret_ids', Sil.Const (Sil.Cfun pn), etl', loc', cf), _, _ + when IList.length ret_ids = IList.length ret_ids' + && IList.length etl' + 1 = IList.length etl -> + let etl1 = match IList.rev etl with (* remove last element *) + | _ :: l -> IList.rev l + | [] -> assert false in + let instr' = Sil.Call (ret_ids, Sil.Const (Sil.Cfun pn), etl1, loc_call, cf) in + found instr instr' + | _ -> () in + Procdesc.iter_instrs do_instr proc_desc; + !modified + +(** Find synthetic (access or bridge) Java methods in the procedure and inline them in the cfg. *) +let proc_inline_synthetic_methods cfg proc_desc : unit = + let instr_inline_synthetic_method = function + | Sil.Call (ret_ids, Sil.Const (Sil.Cfun pn), etl, loc, _) -> + (match Procdesc.find_from_name cfg pn with + | Some pd -> + let is_access = Procname.java_is_access_method pn in + let attributes = Procdesc.get_attributes pd in + let is_synthetic = attributes.ProcAttributes.is_synthetic_method in + let is_bridge = attributes.ProcAttributes.is_bridge_method in + if is_access || is_bridge || is_synthetic + then inline_synthetic_method ret_ids etl pd pn loc + else None + | None -> None) + | _ -> None in + let node_inline_synthetic_methods node = + let modified = ref false in + let do_instr instr = match instr_inline_synthetic_method instr with + | None -> instr + | Some instr' -> + modified := true; + instr' in + let instrs = Node.get_instrs node in + let instrs' = IList.map do_instr instrs in + if !modified then Node.replace_instrs node instrs' in + Procdesc.iter_nodes node_inline_synthetic_methods proc_desc + +(** Inline the java synthetic methods in the cfg *) +let inline_java_synthetic_methods cfg = + let f proc_name proc_desc = + if Procname.is_java proc_name + then proc_inline_synthetic_methods cfg proc_desc in + iter_proc_desc cfg f + (** Save a cfg into a file *) let store_cfg_to_file (filename : DB.filename) (save_sources : bool) (cfg : cfg) = + inline_java_synthetic_methods cfg; if save_sources then save_source_files cfg; if !Config.incremental_procs then begin diff --git a/infer/src/backend/interproc.ml b/infer/src/backend/interproc.ml index 9bd2dc594..91acfbb25 100644 --- a/infer/src/backend/interproc.ml +++ b/infer/src/backend/interproc.ml @@ -1258,7 +1258,6 @@ let do_analysis exe_env = { (Cfg.Procdesc.get_attributes pdesc) with ProcAttributes.err_log = static_err_log; } in - Callbacks.proc_inline_synthetic_methods cfg pdesc; Specs.init_summary (dep, nodes, proc_flags, calls, None, attributes) in