diff --git a/infer/src/cost/cost.ml b/infer/src/cost/cost.ml index a24ccbc82..517a27a96 100644 --- a/infer/src/cost/cost.ml +++ b/infer/src/cost/cost.ml @@ -84,10 +84,18 @@ module InstrBasicCostWithReason = struct CostDomain.of_operation_cost (model model_env ~ret inferbo_mem) | None -> ( match Tenv.get_summary_formals tenv ~get_summary ~get_formals callee_pname with - | `Found ({CostDomain.post= callee_cost_record}, callee_formals) -> - CostDomain.map callee_cost_record ~f:(fun callee_cost -> - instantiate_cost integer_type_widths ~inferbo_caller_mem:inferbo_mem - ~callee_pname ~callee_formals ~params ~callee_cost ~loc ) + | `Found ({CostDomain.post= callee_cost_record}, callee_formals) -> ( + let instantiated_cost = + CostDomain.map callee_cost_record ~f:(fun callee_cost -> + instantiate_cost integer_type_widths ~inferbo_caller_mem:inferbo_mem + ~callee_pname ~callee_formals ~params ~callee_cost ~loc ) + in + match CostDomain.get_operation_cost callee_cost_record with + | {cost; top_pname_opt= None} when BasicCost.is_top cost -> + CostDomain.add_top_pname_opt CostKind.OperationCost instantiated_cost + (Some callee_pname) + | _ -> + instantiated_cost ) | `FoundFromSubclass (callee_pname, {CostDomain.post= callee_cost_record}, callee_formals) -> (* Note: It ignores top cost of subclass to avoid its propagations. *) @@ -178,8 +186,16 @@ module WorstCaseCost = struct let compute tenv extras cfg = let init = CostDomain.zero_record in - InstrCFG.fold_nodes cfg ~init ~f:(fun acc pair -> - exec_node tenv extras pair |> CostDomain.plus acc ) + let cost = + InstrCFG.fold_nodes cfg ~init ~f:(fun acc pair -> + exec_node tenv extras pair |> CostDomain.plus acc ) + in + Option.iter (CostDomain.get_operation_cost cost).top_pname_opt ~f:(fun top_pname -> + ScubaLogging.log_message ~label:"unmodeled_function_top_cost" + ~message:(F.asprintf "Unmodeled Function[Top Cost] : %a" Procname.pp top_pname) ; + Logging.(debug Analysis Verbose) + "@ Unmodeled Function[Top Cost]: %a@\n" Procname.pp top_pname ) ; + cost end let is_report_suppressed pname = diff --git a/infer/src/cost/costDomain.ml b/infer/src/cost/costDomain.ml index 6c8e9efdc..02fcee964 100644 --- a/infer/src/cost/costDomain.ml +++ b/infer/src/cost/costDomain.ml @@ -31,6 +31,8 @@ module BasicCostWithReason = struct {record with cost= BasicCost.subst callee_pname location record.cost eval_sym} + (* When we fold the nodes while traversing the cfg, + make sure we only keep the first top cost callee we see *) let plus record1 record2 = { cost= BasicCost.plus record1.cost record2.cost ; top_pname_opt= Option.first_some record1.top_pname_opt record2.top_pname_opt } @@ -78,6 +80,12 @@ let pp_summary fmt {post} = F.fprintf fmt "@\n Post: %a @\n" VariantCostMap.pp p let get_cost_kind kind cost_record = VariantCostMap.get kind cost_record +let add_top_pname_opt kind cost_record top_pname_opt = + VariantCostMap.update kind + (function Some cost_with_reason -> Some {cost_with_reason with top_pname_opt} | _ -> None) + cost_record + + let get_operation_cost cost_record = get_cost_kind CostKind.OperationCost cost_record let map ~f cost_record = VariantCostMap.map f cost_record diff --git a/infer/src/cost/costDomain.mli b/infer/src/cost/costDomain.mli index f0b7658b8..6b0095b8d 100644 --- a/infer/src/cost/costDomain.mli +++ b/infer/src/cost/costDomain.mli @@ -58,6 +58,8 @@ val pp_summary : F.formatter -> summary -> unit val get_cost_kind : CostKind.t -> t -> BasicCostWithReason.t +val add_top_pname_opt : CostKind.t -> t -> Procname.t option -> t + val get_operation_cost : t -> BasicCostWithReason.t val map : f:(BasicCostWithReason.t -> BasicCostWithReason.t) -> t -> t