Reviewed By: skcho Differential Revision: D18961821 fbshipit-source-id: b90901751master
							parent
							
								
									9ed9363207
								
							
						
					
					
						commit
						1e1d40b460
					
				| @ -1,213 +0,0 @@ | |||||||
| (* |  | ||||||
|  * 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 |  | ||||||
| module F = Format |  | ||||||
| module Domain = LithoDomain |  | ||||||
| 
 |  | ||||||
| (** return true if this function is part of the Litho framework code rather than client code *) |  | ||||||
| let is_function = function |  | ||||||
|   | Typ.Procname.Java java_procname -> ( |  | ||||||
|     match Typ.Procname.Java.get_package java_procname with |  | ||||||
|     | Some "com.facebook.litho" -> |  | ||||||
|         true |  | ||||||
|     | _ -> |  | ||||||
|         false ) |  | ||||||
|   | _ -> |  | ||||||
|       false |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| let is_component_builder procname tenv = |  | ||||||
|   match procname with |  | ||||||
|   | Typ.Procname.Java java_procname -> |  | ||||||
|       PatternMatch.is_subtype_of_str tenv |  | ||||||
|         (Typ.Procname.Java.get_class_type_name java_procname) |  | ||||||
|         "com.facebook.litho.Component$Builder" |  | ||||||
|   | _ -> |  | ||||||
|       false |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| let is_component procname tenv = |  | ||||||
|   match procname with |  | ||||||
|   | Typ.Procname.Java java_procname -> |  | ||||||
|       PatternMatch.is_subtype_of_str tenv |  | ||||||
|         (Typ.Procname.Java.get_class_type_name java_procname) |  | ||||||
|         "com.facebook.litho.Component" |  | ||||||
|   | _ -> |  | ||||||
|       false |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| let is_component_build_method procname tenv = |  | ||||||
|   match Typ.Procname.get_method procname with |  | ||||||
|   | "build" -> |  | ||||||
|       is_component_builder procname tenv |  | ||||||
|   | _ -> |  | ||||||
|       false |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| let is_component_create_method procname tenv = |  | ||||||
|   match Typ.Procname.get_method procname with "create" -> is_component procname tenv | _ -> false |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| let get_component_create_typ_opt procname tenv = |  | ||||||
|   match procname with |  | ||||||
|   | Typ.Procname.Java java_pname when is_component_create_method procname tenv -> |  | ||||||
|       Some (Typ.Procname.Java.get_class_type_name java_pname) |  | ||||||
|   | _ -> |  | ||||||
|       None |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| module type LithoContext = sig |  | ||||||
|   type t |  | ||||||
| 
 |  | ||||||
|   type summary |  | ||||||
| 
 |  | ||||||
|   val field : (Payloads.t, summary option) Field.t |  | ||||||
| 
 |  | ||||||
|   val check_callee : callee_pname:Typ.Procname.t -> tenv:Tenv.t -> summary option -> bool |  | ||||||
| 
 |  | ||||||
|   val satisfies_heuristic : |  | ||||||
|     callee_pname:Typ.Procname.t -> callee_summary_opt:summary option -> Tenv.t -> bool |  | ||||||
| 
 |  | ||||||
|   val should_report : Procdesc.t -> Tenv.t -> bool |  | ||||||
| 
 |  | ||||||
|   val report : summary -> Tenv.t -> Summary.t -> summary |  | ||||||
| 
 |  | ||||||
|   val session_name : string |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| type get_proc_summary_and_formals = |  | ||||||
|   Typ.Procname.t -> (Domain.summary * (Pvar.t * Typ.t) list) option |  | ||||||
| 
 |  | ||||||
| type extras = {get_proc_summary_and_formals: get_proc_summary_and_formals} |  | ||||||
| 
 |  | ||||||
| module TransferFunctions |  | ||||||
|     (CFG : ProcCfg.S) |  | ||||||
|     (LithoContext : LithoContext with type summary = Domain.summary) = |  | ||||||
| struct |  | ||||||
|   module CFG = CFG |  | ||||||
|   module Domain = Domain |  | ||||||
| 
 |  | ||||||
|   module Payload = SummaryPayload.Make (struct |  | ||||||
|     type t = LithoContext.summary |  | ||||||
| 
 |  | ||||||
|     let field = LithoContext.field |  | ||||||
|   end) |  | ||||||
| 
 |  | ||||||
|   type nonrec extras = extras |  | ||||||
| 
 |  | ||||||
|   let apply_callee_summary summary_opt ~caller_pname ~callee_pname ret_id_typ formals actuals astate |  | ||||||
|       = |  | ||||||
|     Option.value_map summary_opt ~default:astate ~f:(fun callee_summary -> |  | ||||||
|         Domain.subst ~formals ~actuals ~ret_id_typ ~caller_pname ~callee_pname ~caller:astate |  | ||||||
|           ~callee:callee_summary ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   let exec_instr astate ProcData.{summary; tenv; extras= {get_proc_summary_and_formals}} _ |  | ||||||
|       (instr : HilInstr.t) : Domain.t = |  | ||||||
|     let caller_pname = Summary.get_proc_name summary in |  | ||||||
|     match instr with |  | ||||||
|     | Call |  | ||||||
|         ( return_base |  | ||||||
|         , Direct callee_pname |  | ||||||
|         , (HilExp.AccessExpression receiver_ae :: _ as actuals) |  | ||||||
|         , _ |  | ||||||
|         , location ) -> |  | ||||||
|         let callee_summary_and_formals_opt = get_proc_summary_and_formals callee_pname in |  | ||||||
|         let callee_summary_opt = Option.map callee_summary_and_formals_opt ~f:fst in |  | ||||||
|         let receiver = |  | ||||||
|           Domain.LocalAccessPath.make_from_access_expression receiver_ae caller_pname |  | ||||||
|         in |  | ||||||
|         if |  | ||||||
|           LithoContext.check_callee ~callee_pname ~tenv callee_summary_opt |  | ||||||
|           (* track callee in order to report respective errors *) |  | ||||||
|           && LithoContext.satisfies_heuristic ~callee_pname ~callee_summary_opt tenv |  | ||||||
|         then |  | ||||||
|           let return_access_path = Domain.LocalAccessPath.make (return_base, []) caller_pname in |  | ||||||
|           match get_component_create_typ_opt callee_pname tenv with |  | ||||||
|           | Some create_typ -> |  | ||||||
|               Domain.call_create return_access_path create_typ location astate |  | ||||||
|           | None -> |  | ||||||
|               if is_component_build_method callee_pname tenv then |  | ||||||
|                 Domain.call_build_method ~ret:return_access_path ~receiver astate |  | ||||||
|               else if is_component_builder callee_pname tenv then |  | ||||||
|                 let callee_prefix = Domain.MethodCallPrefix.make callee_pname location in |  | ||||||
|                 Domain.call_builder ~ret:return_access_path ~receiver callee_prefix astate |  | ||||||
|               else astate |  | ||||||
|         else |  | ||||||
|           (* treat it like a normal call *) |  | ||||||
|           Option.value_map callee_summary_and_formals_opt ~default:astate ~f:(fun (_, formals) -> |  | ||||||
|               apply_callee_summary callee_summary_opt ~caller_pname ~callee_pname return_base |  | ||||||
|                 formals actuals astate ) |  | ||||||
|     | Call (ret_id_typ, Direct callee_pname, actuals, _, _) -> |  | ||||||
|         let callee_summary_and_formals_opt = get_proc_summary_and_formals callee_pname in |  | ||||||
|         let callee_summary_opt = Option.map callee_summary_and_formals_opt ~f:fst in |  | ||||||
|         Option.value_map callee_summary_and_formals_opt ~default:astate ~f:(fun (_, formals) -> |  | ||||||
|             apply_callee_summary callee_summary_opt ~caller_pname ~callee_pname ret_id_typ formals |  | ||||||
|               actuals astate ) |  | ||||||
|     | Assign (lhs_ae, rhs, _) -> |  | ||||||
|         let astate = |  | ||||||
|           match rhs with |  | ||||||
|           | HilExp.AccessExpression rhs_ae -> |  | ||||||
|               (* creating an alias for the rhs binding; assume all reads will now occur through the |  | ||||||
|                  alias. this helps us keep track of chains in cases like tmp = getFoo(); x = tmp; |  | ||||||
|                  tmp.getBar() *) |  | ||||||
|               let lhs_access_path = |  | ||||||
|                 Domain.LocalAccessPath.make |  | ||||||
|                   (HilExp.AccessExpression.to_access_path lhs_ae) |  | ||||||
|                   caller_pname |  | ||||||
|               in |  | ||||||
|               let rhs_access_path = |  | ||||||
|                 Domain.LocalAccessPath.make |  | ||||||
|                   (HilExp.AccessExpression.to_access_path rhs_ae) |  | ||||||
|                   caller_pname |  | ||||||
|               in |  | ||||||
|               Domain.assign ~lhs:lhs_access_path ~rhs:rhs_access_path astate |  | ||||||
|           | _ -> |  | ||||||
|               astate |  | ||||||
|         in |  | ||||||
|         if HilExp.AccessExpression.is_return_var lhs_ae then Domain.call_return astate else astate |  | ||||||
|     | _ -> |  | ||||||
|         astate |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   let pp_session_name _node fmt = F.pp_print_string fmt LithoContext.session_name |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| module MakeAnalyzer (LithoContext : LithoContext with type summary = Domain.summary) = struct |  | ||||||
|   module TF = TransferFunctions (ProcCfg.Normal) (LithoContext) |  | ||||||
|   module A = LowerHil.MakeAbstractInterpreter (TF) |  | ||||||
| 
 |  | ||||||
|   let init_extras summary = |  | ||||||
|     let get_proc_summary_and_formals callee_pname = |  | ||||||
|       Ondemand.analyze_proc_name ~caller_summary:summary callee_pname |  | ||||||
|       |> Option.bind ~f:(fun summary -> |  | ||||||
|              TF.Payload.of_summary summary |  | ||||||
|              |> Option.map ~f:(fun payload -> |  | ||||||
|                     (payload, Summary.get_proc_desc summary |> Procdesc.get_pvar_formals) ) ) |  | ||||||
|     in |  | ||||||
|     {get_proc_summary_and_formals} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   let checker {Callbacks.summary; exe_env} = |  | ||||||
|     let proc_desc = Summary.get_proc_desc summary in |  | ||||||
|     let proc_name = Summary.get_proc_name summary in |  | ||||||
|     let tenv = Exe_env.get_tenv exe_env (Summary.get_proc_name summary) in |  | ||||||
|     let proc_data = ProcData.make summary tenv (init_extras summary) in |  | ||||||
|     let initial = Domain.init tenv proc_name (Procdesc.get_pvar_formals proc_desc) in |  | ||||||
|     match A.compute_post proc_data ~initial with |  | ||||||
|     | Some post -> |  | ||||||
|         let is_void_func = Procdesc.get_ret_type proc_desc |> Typ.is_void in |  | ||||||
|         let post = Domain.get_summary ~is_void_func post in |  | ||||||
|         let post = |  | ||||||
|           if LithoContext.should_report proc_desc tenv then LithoContext.report post tenv summary |  | ||||||
|           else post |  | ||||||
|         in |  | ||||||
|         TF.Payload.update_summary post summary |  | ||||||
|     | None -> |  | ||||||
|         summary |  | ||||||
| end |  | ||||||
					Loading…
					
					
				
		Reference in new issue