|
|
|
@ -9,12 +9,6 @@ open! IStd
|
|
|
|
|
module F = Format
|
|
|
|
|
module Domain = LithoDomain
|
|
|
|
|
|
|
|
|
|
module Payload = SummaryPayload.Make (struct
|
|
|
|
|
type t = Domain.summary
|
|
|
|
|
|
|
|
|
|
let field = Payloads.Fields.litho_required_props
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
(* VarProp is only for props that have a varArg parameter like
|
|
|
|
|
@Prop(varArg = "var_prop") whereas Prop is for everything except. *)
|
|
|
|
|
type required_prop = Prop of string | VarProp of {prop: string; var_prop: string}
|
|
|
|
@ -65,7 +59,7 @@ let get_required_props typename tenv =
|
|
|
|
|
[]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let report_missing_required_prop summary prop parent_typename ~create_loc call_chain =
|
|
|
|
|
let report_missing_required_prop proc_attrs err_log prop parent_typename ~create_loc call_chain =
|
|
|
|
|
let message =
|
|
|
|
|
let prop_string =
|
|
|
|
|
match prop with
|
|
|
|
@ -88,7 +82,8 @@ let report_missing_required_prop summary prop parent_typename ~create_loc call_c
|
|
|
|
|
in
|
|
|
|
|
Errlog.make_trace_element 0 location call_msg [] )
|
|
|
|
|
in
|
|
|
|
|
SummaryReporting.log_error summary ~loc:create_loc ~ltr IssueType.missing_required_prop message
|
|
|
|
|
Reporting.log_error proc_attrs err_log ~loc:create_loc ~ltr IssueType.missing_required_prop
|
|
|
|
|
message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let has_prop prop_set prop =
|
|
|
|
@ -184,26 +179,27 @@ let should_report proc_desc tenv =
|
|
|
|
|
(not (is_litho_function pname)) && not (is_component_build_method pname tenv)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let report astate tenv summary =
|
|
|
|
|
let report {InterproceduralAnalysis.proc_desc; tenv; err_log} astate =
|
|
|
|
|
let check_on_string_set parent_typename create_loc call_chain prop_set =
|
|
|
|
|
let required_props = get_required_props parent_typename tenv in
|
|
|
|
|
let attrs = Procdesc.get_attributes proc_desc in
|
|
|
|
|
List.iter required_props ~f:(fun required_prop ->
|
|
|
|
|
if not (has_prop prop_set required_prop) then
|
|
|
|
|
report_missing_required_prop summary required_prop parent_typename ~create_loc call_chain
|
|
|
|
|
)
|
|
|
|
|
report_missing_required_prop attrs err_log required_prop parent_typename ~create_loc
|
|
|
|
|
call_chain )
|
|
|
|
|
in
|
|
|
|
|
Domain.check_required_props ~check_on_string_set astate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type get_proc_summary_and_formals = Procname.t -> (Domain.summary * (Pvar.t * Typ.t) list) option
|
|
|
|
|
type analysis_data =
|
|
|
|
|
{ analysis_data: LithoDomain.summary InterproceduralAnalysis.t
|
|
|
|
|
; get_proc_summary_and_formals: Procname.t -> (Domain.summary * (Pvar.t * Typ.t) list) option }
|
|
|
|
|
|
|
|
|
|
module TransferFunctions = struct
|
|
|
|
|
module CFG = ProcCfg.Normal
|
|
|
|
|
module Domain = LithoDomain
|
|
|
|
|
|
|
|
|
|
type extras = {get_proc_summary_and_formals: get_proc_summary_and_formals}
|
|
|
|
|
|
|
|
|
|
type analysis_data = extras ProcData.t
|
|
|
|
|
type nonrec analysis_data = analysis_data
|
|
|
|
|
|
|
|
|
|
let apply_callee_summary summary_opt callsite ~caller_pname ~callee_pname ret_id_typ formals
|
|
|
|
|
actuals astate =
|
|
|
|
@ -212,9 +208,9 @@ module TransferFunctions = struct
|
|
|
|
|
~caller:astate ~callee:callee_summary )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let exec_instr astate ProcData.{summary; tenv; extras= {get_proc_summary_and_formals}} _
|
|
|
|
|
let exec_instr astate {analysis_data= {proc_desc; tenv}; get_proc_summary_and_formals} _
|
|
|
|
|
(instr : HilInstr.t) : Domain.t =
|
|
|
|
|
let caller_pname = Summary.get_proc_name summary in
|
|
|
|
|
let caller_pname = Procdesc.get_proc_name proc_desc in
|
|
|
|
|
match instr with
|
|
|
|
|
| Call
|
|
|
|
|
( return_base
|
|
|
|
@ -285,31 +281,25 @@ end
|
|
|
|
|
|
|
|
|
|
module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions)
|
|
|
|
|
|
|
|
|
|
let init_extras summary =
|
|
|
|
|
let init_analysis_data ({InterproceduralAnalysis.analyze_dependency} as analysis_data) =
|
|
|
|
|
let get_proc_summary_and_formals callee_pname =
|
|
|
|
|
Payload.read_full ~caller_summary:summary ~callee_pname
|
|
|
|
|
analyze_dependency callee_pname
|
|
|
|
|
|> Option.map ~f:(fun (callee_pdesc, callee_summary) ->
|
|
|
|
|
(callee_summary, Procdesc.get_pvar_formals callee_pdesc) )
|
|
|
|
|
in
|
|
|
|
|
{TransferFunctions.get_proc_summary_and_formals}
|
|
|
|
|
{analysis_data; 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.summary; tenv; extras= init_extras summary} in
|
|
|
|
|
let checker ({InterproceduralAnalysis.proc_desc; tenv} as analysis_data) =
|
|
|
|
|
let proc_name = Procdesc.get_proc_name proc_desc in
|
|
|
|
|
let ret_path =
|
|
|
|
|
let ret_var = Procdesc.get_ret_var proc_desc in
|
|
|
|
|
let ret_typ = Procdesc.get_ret_type proc_desc in
|
|
|
|
|
Domain.LocalAccessPath.make_from_pvar ret_var ret_typ proc_name
|
|
|
|
|
in
|
|
|
|
|
let initial = Domain.init tenv proc_name (Procdesc.get_pvar_formals proc_desc) ret_path in
|
|
|
|
|
match Analyzer.compute_post proc_data ~initial proc_desc 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 should_report proc_desc tenv then report post tenv summary else post in
|
|
|
|
|
Payload.update_summary post summary
|
|
|
|
|
| None ->
|
|
|
|
|
summary
|
|
|
|
|
Analyzer.compute_post (init_analysis_data analysis_data) ~initial proc_desc
|
|
|
|
|
|> Option.map ~f:(fun 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
|
|
|
|
|
if should_report proc_desc tenv then report analysis_data post else post )
|
|
|
|
|