You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.9 KiB
98 lines
3.9 KiB
(*
|
|
* Copyright (c) 2017 - present Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*)
|
|
(* Given two lists of tuples (exp1, var1, typ1) and (exp2, var2, typ2)
|
|
append the lists avoiding duplicates, where if the variables exist we check their
|
|
equality, otherwise we check the equality of the expressions. This is to avoid
|
|
adding the same captured variable twice. *)
|
|
let append_no_duplicates_vars list1 list2 =
|
|
let eq (exp1, var1_opt, _) (exp2, var2_opt, _) =
|
|
match (var1_opt, var2_opt) with
|
|
| Some var1, Some var2 ->
|
|
Pvar.equal var1 var2
|
|
| None, None ->
|
|
Exp.equal exp1 exp2
|
|
| _ ->
|
|
false
|
|
in
|
|
IList.append_no_duplicates eq list1 list2
|
|
|
|
|
|
(* Given a list of actual parameters for a function, replaces the closures with the
|
|
captured variables, avoiding adding the same captured variable twice. *)
|
|
let get_extended_args_for_method_with_block_analysis act_params =
|
|
let ext_actuals = List.map ~f:(fun (exp, typ) -> (exp, None, typ)) act_params in
|
|
let args_and_captured =
|
|
List.fold ext_actuals ~init:[] ~f:(fun all_args act_param ->
|
|
match act_param with
|
|
| Exp.Closure cl, _, _ ->
|
|
let captured =
|
|
List.map ~f:(fun (exp, var, typ) -> (exp, Some var, typ)) cl.captured_vars
|
|
in
|
|
append_no_duplicates_vars all_args captured
|
|
| _ ->
|
|
append_no_duplicates_vars all_args [act_param] )
|
|
in
|
|
List.map ~f:(fun (exp, _, typ) -> (exp, typ)) args_and_captured
|
|
|
|
|
|
let resolve_method_with_block_args_and_analyze caller_pdesc pname act_params =
|
|
let pdesc_opt =
|
|
match Specs.get_summary pname with
|
|
| Some summary ->
|
|
Some (Specs.get_proc_desc summary)
|
|
| None ->
|
|
Ondemand.get_proc_desc pname
|
|
in
|
|
match pdesc_opt with
|
|
| Some pdesc
|
|
when Procdesc.is_defined pdesc
|
|
&& Int.equal (List.length (Procdesc.get_formals pdesc)) (List.length act_params)
|
|
(* only specialize defined methods, and when formals and actuals have the same length *)
|
|
-> (
|
|
(* a list with the same length of the actual params of the function,
|
|
containing either a Closure or None. *)
|
|
let block_args =
|
|
List.map act_params ~f:(function
|
|
| Exp.Closure cl, _ when Typ.Procname.is_objc_block cl.name ->
|
|
Some cl
|
|
| _ ->
|
|
None )
|
|
in
|
|
(* name for the specialized method instantiated with block arguments *)
|
|
let pname_with_block_args =
|
|
let block_name_args =
|
|
List.filter_map block_args ~f:(function
|
|
| Some (cl: Exp.closure) ->
|
|
Some (Typ.Procname.block_name_of_procname cl.name)
|
|
| None ->
|
|
None )
|
|
in
|
|
Typ.Procname.with_block_parameters pname block_name_args
|
|
in
|
|
(* new procdesc cloned from the original one, where the block parameters have been
|
|
replaced by the block arguments. The formals have also been expanded with the captured variables *)
|
|
let specialized_pdesc =
|
|
Cfg.specialize_with_block_args pdesc pname_with_block_args block_args
|
|
in
|
|
Logging.(debug Analysis Verbose) "Instructions of specialized method:@." ;
|
|
Procdesc.iter_instrs
|
|
(fun _ instr -> Logging.(debug Analysis Verbose) "%a@." (Sil.pp_instr Pp.text) instr)
|
|
specialized_pdesc ;
|
|
Logging.(debug Analysis Verbose) "End of instructions@." ;
|
|
match Ondemand.analyze_proc_desc caller_pdesc specialized_pdesc with
|
|
| Some summary ->
|
|
(* Since the closures in the formals were replaced by the captured variables,
|
|
we do the same with the actual arguments *)
|
|
let extended_args = get_extended_args_for_method_with_block_analysis act_params in
|
|
Some (summary, extended_args)
|
|
| None ->
|
|
None )
|
|
| _ ->
|
|
None
|