Reviewed By: jvillard Differential Revision: D13449603 fbshipit-source-id: a253ef70bmaster
parent
52e09aed13
commit
bb1a19b6f9
@ -0,0 +1,91 @@
|
||||
(*
|
||||
* Copyright (c) 2018-present, Facebook, Inc.
|
||||
*
|
||||
* 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 L = Logging
|
||||
module SPath = Symb.SymbolPath
|
||||
module FormalTyps = Caml.Map.Make (Pvar)
|
||||
|
||||
type t =
|
||||
{ typ_of_param_path: SPath.partial -> Typ.t option
|
||||
; may_last_field: SPath.partial -> bool
|
||||
; entry_location: Location.t
|
||||
; integer_type_widths: Typ.IntegerWidths.t }
|
||||
|
||||
let mk pdesc =
|
||||
let formal_typs =
|
||||
List.fold (Procdesc.get_pvar_formals pdesc) ~init:FormalTyps.empty ~f:(fun acc (formal, typ) ->
|
||||
FormalTyps.add formal typ acc )
|
||||
in
|
||||
fun tenv integer_type_widths ->
|
||||
let rec typ_of_param_path = function
|
||||
| SPath.Pvar x ->
|
||||
FormalTyps.find_opt x formal_typs
|
||||
| SPath.Deref (_, x) ->
|
||||
Option.map (typ_of_param_path x) ~f:(fun typ ->
|
||||
match typ.Typ.desc with
|
||||
| Tptr (typ, _) ->
|
||||
typ
|
||||
| Tarray {elt} ->
|
||||
elt
|
||||
| Tvoid ->
|
||||
Typ.void
|
||||
| _ ->
|
||||
L.(die InternalError) "Untyped expression is given." )
|
||||
| SPath.Field (fn, x) ->
|
||||
let lookup = Tenv.lookup tenv in
|
||||
Option.map (typ_of_param_path x) ~f:(Typ.Struct.fld_typ ~lookup ~default:Typ.void fn)
|
||||
| SPath.Callsite {ret_typ} ->
|
||||
Some ret_typ
|
||||
in
|
||||
let is_last_field fn (fields : Typ.Struct.field list) =
|
||||
Option.value_map (List.last fields) ~default:false ~f:(fun (last_fn, _, _) ->
|
||||
Typ.Fieldname.equal fn last_fn )
|
||||
in
|
||||
let rec may_last_field = function
|
||||
| SPath.Pvar _ | SPath.Deref _ | SPath.Callsite _ ->
|
||||
true
|
||||
| SPath.Field (fn, x) ->
|
||||
may_last_field x
|
||||
&& Option.value_map ~default:true (typ_of_param_path x) ~f:(fun parent_typ ->
|
||||
match parent_typ.Typ.desc with
|
||||
| Tstruct typename ->
|
||||
let opt_struct = Tenv.lookup tenv typename in
|
||||
Option.value_map opt_struct ~default:false ~f:(fun str ->
|
||||
is_last_field fn str.Typ.Struct.fields )
|
||||
| _ ->
|
||||
true )
|
||||
in
|
||||
let entry_location = Procdesc.Node.get_loc (Procdesc.get_start_node pdesc) in
|
||||
{typ_of_param_path; may_last_field; entry_location; integer_type_widths}
|
||||
|
||||
|
||||
let canonical_path typ_of_param_path path =
|
||||
let module KnownFields = Caml.Map.Make (struct
|
||||
type t = Typ.t option * Typ.Fieldname.t [@@deriving compare]
|
||||
end) in
|
||||
let rec helper path =
|
||||
match path with
|
||||
| SPath.Pvar _ | SPath.Callsite _ ->
|
||||
(None, KnownFields.empty)
|
||||
| SPath.Deref (deref_kind, ptr) ->
|
||||
let ptr_opt, known_fields = helper ptr in
|
||||
(Option.map ptr_opt ~f:(fun ptr -> SPath.deref ~deref_kind ptr), known_fields)
|
||||
| SPath.Field (fn, struct_path) -> (
|
||||
let struct_path_opt, known_fields = helper struct_path in
|
||||
let key = (typ_of_param_path (Option.value ~default:struct_path struct_path_opt), fn) in
|
||||
match KnownFields.find_opt key known_fields with
|
||||
| Some _ as canonicalized ->
|
||||
(canonicalized, known_fields)
|
||||
| None ->
|
||||
let field_path =
|
||||
Option.value_map struct_path_opt ~default:path ~f:(fun struct_path ->
|
||||
SPath.field struct_path fn )
|
||||
in
|
||||
(None, KnownFields.add key field_path known_fields) )
|
||||
in
|
||||
Option.value (helper path |> fst) ~default:path
|
Loading…
Reference in new issue