[typ][fieldname] simplify and streamline interface

Summary:
Remove Clang and Java submodules of Typ.Fieldname. They are unnecessary and they reflect a fake dichotomy: there is only one fieldname type.  To distinguish between fields of Java classes and other C constructs, there is a helper function provided, but the idea is simple: obtain the class type the field belongs to, and check if it's a Java class.

This diff still preserves behaviour, but removes as many functions as possible from the interface, to leave a small surface.

Reviewed By: mityal

Differential Revision: D18962423

fbshipit-source-id: ffe6933ee
master
Nikos Gorogiannis 5 years ago committed by Facebook Github Bot
parent c45b55bff1
commit 59a95b316c

@ -294,7 +294,7 @@ let inner_class_normalize p =
( ( (Var.ProgramVar pvar as root)
, ({desc= Tptr (({desc= Tstruct name} as cls), pkind)} as ptr) )
, FieldAccess first :: accesses )
when Pvar.is_this pvar && Fieldname.Java.is_outer_instance first ->
when Pvar.is_this pvar && Fieldname.is_java_outer_instance first ->
Name.Java.get_outer_class name
|> Option.map ~f:(fun outer_name ->
let outer_class = mk ~default:cls (Tstruct outer_name) in
@ -305,7 +305,7 @@ let inner_class_normalize p =
| Some
( (Var.ProgramVar pvar, ({desc= Tptr (({desc= Tstruct name} as cls), pkind)} as ptr))
, FieldAccess first :: accesses )
when is_synthetic_this pvar && Fieldname.Java.is_outer_instance first ->
when is_synthetic_this pvar && Fieldname.is_java_outer_instance first ->
Name.Java.get_outer_class name
|> Option.bind ~f:(fun outer_name ->
let outer_class = mk ~default:cls (Tstruct outer_name) in

@ -473,6 +473,8 @@ module Name = struct
let java_lang_object = from_string "java.lang.Object"
let java_lang_string = from_string "java.lang.String"
let split_typename typename = Split.of_string (name typename)
let get_outer_class class_name =
@ -1422,6 +1424,12 @@ end
module Fieldname = struct
type t = {class_name: Name.t; field_name: string} [@@deriving compare, equal]
let make class_name field_name = {class_name; field_name}
let get_class_name {class_name} = class_name
let get_field_name {field_name} = field_name
let is_java {class_name} = Name.Java.is_class class_name
module T = struct
@ -1463,43 +1471,17 @@ module Fieldname = struct
(if is_java field then dot_join (Name.name class_name) field_name else field_name)
let clang_get_qual_class ({class_name} as field) =
if is_java field then None else Some (Name.qual_name class_name)
module Clang = struct
let from_class_name class_name field_name = {class_name; field_name}
end
module Java = struct
let from_class_and_field ~class_name ~field_name =
if String.is_empty class_name then
L.die InternalError "Typ.Fieldname.Java classname cannot be empty@\n"
else {class_name= Name.Java.from_string class_name; field_name}
let is_captured_parameter ({field_name} as field) =
is_java field && String.is_prefix ~prefix:"val$" field_name
let is_java_captured_parameter ({field_name} as field) =
is_java field && String.is_prefix ~prefix:"val$" field_name
let get_class ({class_name} as field) =
if is_java field then Name.name class_name
else L.die InternalError "get_class: fieldname %a is not Java@\n" pp field
let get_field ({field_name} as field) =
if is_java field then field_name
else L.die InternalError "get_field: fieldname %a is not Java@\n" pp field
let is_outer_instance ({field_name} as field) =
is_java field
&&
let this = "this$" in
let last_char = field_name.[String.length field_name - 1] in
(last_char >= '0' && last_char <= '9')
&& String.is_suffix field_name ~suffix:(this ^ String.of_char last_char)
end
let is_java_outer_instance ({field_name} as field) =
is_java field
&&
let this = "this$" in
let last_char = field_name.[String.length field_name - 1] in
(last_char >= '0' && last_char <= '9')
&& String.is_suffix field_name ~suffix:(this ^ String.of_char last_char)
end
module Struct = struct

@ -237,6 +237,8 @@ module Name : sig
val java_lang_cloneable : t
val java_lang_class : t
val java_lang_string : t
end
module Cpp : sig
@ -637,6 +639,13 @@ module Fieldname : sig
(** Names for fields of class/struct/union *)
type t [@@deriving compare, equal]
val make : Name.t -> string -> t
(** create a field of the given class and fieldname *)
val get_class_name : t -> Name.t
val get_field_name : t -> string
val is_java : t -> bool
module Set : Caml.Set.S with type elt = t
@ -645,26 +654,12 @@ module Fieldname : sig
module Map : Caml.Map.S with type key = t
(** Map for fieldnames *)
module Clang : sig
val from_class_name : Name.t -> string -> t
end
module Java : sig
val from_class_and_field : class_name:string -> field_name:string -> t
val is_captured_parameter : t -> bool
(** Check if field is a captured parameter *)
val get_class : t -> string
(** The class part of the fieldname *)
val is_java_captured_parameter : t -> bool
(** Check if field is a captured parameter *)
val get_field : t -> string
(** The last component of the fieldname *)
val is_outer_instance : t -> bool
(** Check if the field is the synthetic this$n of a nested class, used to access the n-th outer
val is_java_outer_instance : t -> bool
(** Check if the field is the synthetic this$n of a nested class, used to access the n-th outer
instance. *)
end
val to_string : t -> string
(** Convert a field name to a string. *)
@ -679,9 +674,6 @@ module Fieldname : sig
val pp : Format.formatter -> t -> unit
(** Pretty print a field name. *)
val clang_get_qual_class : t -> QualifiedCppName.t option
(** get qualified classname of a field if it's coming from clang frontend. returns None otherwise *)
end
module Struct : sig

@ -33,7 +33,6 @@ let is_vector_method pname = is_method_of_objc_cpp_class pname vector_matcher
let is_special_field matcher field_name_opt field =
let field_name = Typ.Fieldname.to_flat_string field in
let class_qual_opt = Typ.Fieldname.clang_get_qual_class field in
let field_ok =
match field_name_opt with
| Some field_name' ->
@ -41,7 +40,9 @@ let is_special_field matcher field_name_opt field =
| None ->
true
in
field_ok && Option.value_map ~f:(is_one_of_classes matcher) ~default:false class_qual_opt
field_ok
&& (not (Typ.Fieldname.is_java field))
&& Typ.Fieldname.get_class_name field |> Typ.Name.qual_name |> is_one_of_classes matcher
(** Check whether the hpred is a |-> representing a resource in the Racquire state *)

@ -2293,9 +2293,7 @@ and sigma_imply tenv calc_index_frame calc_missing subs prop1 sigma2 : subst2 *
Sil.Earray (Exp.int len, [(index, Sil.Eexp (Exp.zero, Sil.inst_none))], Sil.inst_none)
| Java ->
let mk_fld_sexp field_name =
let fld =
Typ.Fieldname.Java.from_class_and_field ~class_name:"java.lang.String" ~field_name
in
let fld = Typ.Fieldname.make Typ.Name.Java.java_lang_string field_name in
let se = Sil.Eexp (Exp.Var (Ident.create_fresh Ident.kprimed), Sil.Inone) in
(fld, se)
in
@ -2311,7 +2309,7 @@ and sigma_imply tenv calc_index_frame calc_missing subs prop1 sigma2 : subst2 *
; dynamic_length= None
; subtype= Subtype.exact }
| Java ->
let object_type = Typ.Name.Java.from_string "java.lang.String" in
let object_type = Typ.Name.Java.java_lang_string in
Exp.Sizeof
{ typ= Typ.mk (Tstruct object_type)
; nbytes= None
@ -2326,13 +2324,12 @@ and sigma_imply tenv calc_index_frame calc_missing subs prop1 sigma2 : subst2 *
let sexp =
(* TODO: add appropriate fields *)
Sil.Estruct
( [ ( Typ.Fieldname.Java.from_class_and_field ~class_name:"java.lang.Class"
~field_name:"name"
( [ ( Typ.Fieldname.make Typ.Name.Java.java_lang_class "name"
, Sil.Eexp (Exp.Const (Const.Cstr s), Sil.Inone) ) ]
, Sil.inst_none )
in
let class_texp =
let class_type = Typ.Name.Java.from_string "java.lang.Class" in
let class_type = Typ.Name.Java.java_lang_class in
Exp.Sizeof
{ typ= Typ.mk (Tstruct class_type)
; nbytes= None

@ -779,7 +779,7 @@ let add_guarded_by_constraints tenv prop lexp pdesc =
match extract_guarded_by_str item_annot with
| Some "this" ->
(* expand "this" into <classname>.this *)
Some (Printf.sprintf "%s.this" (Typ.Fieldname.Java.get_class fld))
Some (Printf.sprintf "%s.this" (Typ.Name.name (Typ.Fieldname.get_class_name fld)))
| guarded_by_str_opt ->
guarded_by_str_opt )
| _ ->
@ -846,7 +846,7 @@ let add_guarded_by_constraints tenv prop lexp pdesc =
(* if the guarded-by string is "OuterClass.this", look for "this$n" for some n.
note that this is a bit sketchy when there are mutliple this$n's, but there's
nothing we can do to disambiguate them. *)
get_fld_strexp_and_typ typ (fun f _ -> Typ.Fieldname.Java.is_outer_instance f) flds
get_fld_strexp_and_typ typ (fun f _ -> Typ.Fieldname.is_java_outer_instance f) flds
| None ->
(* can't find an exact match. try a different convention. *)
match_on_field_type typ flds

@ -212,12 +212,9 @@ module TransferFunctions = struct
let assign_java_enum_values id callee_pname mem =
match Typ.Procname.get_class_type_name callee_pname with
| Some (JavaClass class_name) ->
| Some (JavaClass class_name as typename) ->
let class_var = Loc.of_var (Var.of_pvar (Pvar.mk_global class_name)) in
let fn =
Typ.Fieldname.Java.from_class_and_field ~class_name:(Mangled.to_string class_name)
~field_name:"$VALUES"
in
let fn = Typ.Fieldname.make typename "$VALUES" in
let v = Dom.Mem.find (Loc.append_field class_var ~fn) mem in
Dom.Mem.add_stack (Loc.of_id id) v mem
| _ ->

@ -33,9 +33,9 @@ let mk, get_type =
match cpp_classname with
| None ->
let class_name, field_name = String.rsplit2_exn ~on:'.' (class_name ^ "." ^ name) in
Typ.Fieldname.Java.from_class_and_field ~class_name ~field_name
Typ.Fieldname.make (Typ.Name.Java.from_string class_name) field_name
| Some classname ->
Typ.Fieldname.Clang.from_class_name classname name
Typ.Fieldname.make classname name
in
types := Typ.Fieldname.Map.add fieldname typ !types ;
fieldname

@ -475,7 +475,7 @@ module Split = struct
let std_vector ~adds_at_least_one {exp= vector_exp; typ= vector_typ} location mem =
let increment = if adds_at_least_one then Dom.Val.Itv.pos else Dom.Val.Itv.nat in
let vector_type_name = Option.value_exn (vector_typ |> Typ.strip_ptr |> Typ.name) in
let size_field = Typ.Fieldname.Clang.from_class_name vector_type_name "infer_size" in
let size_field = Typ.Fieldname.make vector_type_name "infer_size" in
let vector_size_locs = Sem.eval_locs vector_exp mem |> PowLoc.append_field ~fn:size_field in
let f_trace _ traces = Trace.(Set.add_elem location (through ~risky_fun:None)) traces in
Dom.Mem.transform_mem ~f:(Dom.Val.plus_a ~f_trace increment) vector_size_locs mem

@ -47,7 +47,7 @@ let get_required_props typename tenv =
List.filter_map
~f:(fun (fieldname, _, annot) ->
if is_required annot then
let prop = Typ.Fieldname.Java.get_field fieldname in
let prop = Typ.Fieldname.get_field_name fieldname in
let var_prop_opt = get_var_args annot in
Some
(Option.value_map var_prop_opt ~default:(Prop prop) ~f:(fun var_prop ->

@ -61,7 +61,7 @@ let callback_fragment_retains_view_java java_pname {Callbacks.summary; exe_env}
in
(* is [fldname] a View type declared by [class_typename]? *)
let is_declared_view_typ class_typename (fldname, fld_typ, _) =
let fld_classname = Typ.Name.Java.from_string (Typ.Fieldname.Java.get_class fldname) in
let fld_classname = Typ.Fieldname.get_class_name fldname in
Typ.Name.equal fld_classname class_typename && fld_typ_is_view fld_typ
in
if is_on_destroy_view then

@ -123,7 +123,7 @@ let modelled_field class_name_info =
let modelled_field_in_class res (class_name, field_name, typ) =
if String.equal class_name class_name_info.Clang_ast_t.ni_name then
let class_tname = Typ.Name.Objc.from_string class_name in
let name = Typ.Fieldname.Clang.from_class_name class_tname field_name in
let name = Typ.Fieldname.make class_tname field_name in
(name, typ, Annot.Item.empty) :: res
else res
in

@ -63,9 +63,7 @@ let list_range i j =
aux j []
let mk_class_field_name class_tname field_name =
Typ.Fieldname.Clang.from_class_name class_tname field_name
let mk_class_field_name class_tname field_name = Typ.Fieldname.make class_tname field_name
let is_cpp_translation translation_unit_context =
let lang = translation_unit_context.CFrontend_config.lang in

@ -455,7 +455,7 @@ let is_synchronized_container callee_pname (access_exp : HilExp.AccessExpression
with
| Access.FieldAccess base_field :: Access.FieldAccess container_field :: _
when Typ.Procname.is_java callee_pname ->
let base_typename = Typ.Name.Java.from_string (Typ.Fieldname.Java.get_class base_field) in
let base_typename = Typ.Fieldname.get_class_name base_field in
is_annotated_synchronized base_typename container_field tenv
| [Access.FieldAccess container_field] -> (
match (AccessExpression.get_base access_exp |> snd).desc with

@ -40,8 +40,9 @@ let secs_of_timeunit =
in
let str_of_access_path = function
| _, [AccessPath.FieldAccess field]
when String.equal "java.util.concurrent.TimeUnit" (Typ.Fieldname.Java.get_class field) ->
Some (Typ.Fieldname.Java.get_field field)
when String.equal "java.util.concurrent.TimeUnit"
(Typ.Name.name (Typ.Fieldname.get_class_name field)) ->
Some (Typ.Fieldname.get_field_name field)
| _ ->
None
in
@ -279,8 +280,8 @@ type scheduler_thread_constraint = ForUIThread | ForNonUIThread | ForUnknownThre
let rec get_executor_thread_annotation_constraint tenv (receiver : HilExp.AccessExpression.t) =
match receiver with
| FieldOffset (_, field_name) when Typ.Fieldname.is_java field_name ->
Typ.Fieldname.Java.get_class field_name
|> Typ.Name.Java.from_string |> Tenv.lookup tenv
Typ.Fieldname.get_class_name field_name
|> Tenv.lookup tenv
|> Option.map ~f:(fun (tstruct : Typ.Struct.t) -> tstruct.fields @ tstruct.statics)
|> Option.bind ~f:(List.find ~f:(fun (fld, _, _) -> Typ.Fieldname.equal fld field_name))
|> Option.bind ~f:(fun (_, _, annot) ->

@ -203,7 +203,7 @@ let get_method_kind m =
let create_fieldname cn fs =
let field_name = JBasics.fs_name fs in
let class_name = JBasics.cn_name cn in
Typ.Fieldname.Java.from_class_and_field ~class_name ~field_name
Typ.Fieldname.make (Typ.Name.Java.from_string class_name) field_name
let create_sil_class_field cn {Javalib.cf_signature; cf_annotations; cf_kind} =
@ -396,7 +396,7 @@ let get_class_type program tenv cn =
(** return true if [field_name] is the autogenerated C.$assertionsDisabled field for class C *)
let is_autogenerated_assert_field field_name =
String.equal (Typ.Fieldname.Java.get_field field_name) "$assertionsDisabled"
String.equal (Typ.Fieldname.get_field_name field_name) "$assertionsDisabled"
(** translate an object type *)

@ -162,7 +162,7 @@ let pretty_field_name proc_data field_name =
match Summary.get_proc_name proc_data.ProcData.summary with
| Typ.Procname.Java jproc_name ->
let proc_class_name = Typ.Procname.Java.get_class_name jproc_name in
let field_class_name = Typ.Fieldname.Java.get_class field_name in
let field_class_name = Typ.Fieldname.get_class_name field_name |> Typ.Name.name in
if String.equal proc_class_name field_class_name then Typ.Fieldname.to_flat_string field_name
else Typ.Fieldname.to_simplified_string field_name
| _ ->
@ -174,7 +174,7 @@ let pretty_field_name proc_data field_name =
let is_outside_codebase proc_name field_name =
match proc_name with
| Typ.Procname.Java _ ->
Typ.Name.Java.is_external_classname (Typ.Fieldname.Java.get_class field_name)
Typ.Name.Java.is_external_classname (Typ.Name.name (Typ.Fieldname.get_class_name field_name))
| _ ->
false
@ -199,7 +199,7 @@ let checker {Callbacks.summary; exe_env} =
do, so let's do it in ad hoc way.
*)
()
| Some (field_name, _) when Typ.Fieldname.Java.is_captured_parameter field_name ->
| Some (field_name, _) when Typ.Fieldname.is_java_captured_parameter field_name ->
(* Skip reporting when field comes from generated code *)
()
| Some (field_name, _) ->

@ -158,7 +158,7 @@ let check_field_assignment ~is_strict_mode tenv find_canonical_duplicate curr_pd
let should_report =
(not (AndroidFramework.is_destroy_method curr_pname))
&& PatternMatch.type_is_class t_lhs
&& (not (Typ.Fieldname.Java.is_outer_instance fname))
&& (not (Typ.Fieldname.is_java_outer_instance fname))
&& (not (field_is_injector_readwrite ()))
&& not (field_is_in_cleanup_context ())
in
@ -281,14 +281,14 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
in
let should_check_field_initialization =
let in_current_class =
let fld_cname = Typ.Fieldname.Java.get_class field_name in
String.equal (Typ.Name.name name) fld_cname
let fld_cname = Typ.Fieldname.get_class_name field_name in
Typ.Name.equal name fld_cname
in
(not is_injector_readonly_annotated)
(* primitive types can not be null so initialization check is not needed *)
&& PatternMatch.type_is_class field_type
&& in_current_class
&& not (Typ.Fieldname.Java.is_outer_instance field_name)
&& not (Typ.Fieldname.is_java_outer_instance field_name)
in
if should_check_field_initialization then (
(* Check if non-null field is not initialized. *)

@ -320,7 +320,7 @@ let convert_complex_exp_to_pvar tenv idenv curr_pname
update_typestate_fld ~is_assignment tenv loc typestate pvar inner_origin fn typ
in
(Exp.Lvar pvar, typestate')
| Exp.Lfield (_exp', fn', _) when Typ.Fieldname.Java.is_outer_instance fn' ->
| Exp.Lfield (_exp', fn', _) when Typ.Fieldname.is_java_outer_instance fn' ->
(* handle double dereference when accessing a field from an outer class *)
let fld_name = Typ.Fieldname.to_string fn' ^ "_" ^ Typ.Fieldname.to_string fn in
let pvar = Pvar.mk (Mangled.from_string fld_name) curr_pname in

@ -90,7 +90,7 @@ end
module StdAtomicInteger = struct
let internal_int =
Typ.Fieldname.Clang.from_class_name
Typ.Fieldname.make
(Typ.CStruct (QualifiedCppName.of_list ["std"; "atomic"]))
"__infer_model_backing_int"
@ -213,7 +213,7 @@ end
module StdBasicString = struct
let internal_string =
Typ.Fieldname.Clang.from_class_name
Typ.Fieldname.make
(Typ.CStruct (QualifiedCppName.of_list ["std"; "basic_string"]))
"__infer_model_backing_string"
@ -270,7 +270,7 @@ end
module StdVector = struct
let internal_array =
Typ.Fieldname.Clang.from_class_name
Typ.Fieldname.make
(Typ.CStruct (QualifiedCppName.of_list ["std"; "vector"]))
"__infer_model_backing_array"

@ -28,7 +28,7 @@ module Closures = struct
let fake_capture_field_prefix = "__capture_"
let mk_fake_field ~id =
Typ.Fieldname.Clang.from_class_name
Typ.Fieldname.make
(Typ.CStruct (QualifiedCppName.of_list ["std"; "function"]))
(Printf.sprintf "%s%d" fake_capture_field_prefix id)

@ -35,7 +35,7 @@ let topl_class_exp =
let make_field field_name =
Typ.Fieldname.Java.from_class_and_field ~class_name:ToplName.topl_property ~field_name
Typ.Fieldname.make (Typ.Name.Java.from_string ToplName.topl_property) field_name
let static_var x : Exp.t = Exp.Lfield (topl_class_exp, make_field x, topl_class_typ)

@ -13,7 +13,7 @@ let make_base ?(typ = Typ.mk Tvoid) base_str = AccessPath.base_of_pvar (make_var
let make_fieldname field_name =
assert (not (String.contains field_name '.')) ;
Typ.Fieldname.Java.from_class_and_field ~class_name:"SomeClass" ~field_name
Typ.Fieldname.make (Typ.Name.Java.from_string "SomeClass") field_name
let make_field_access access_str = AccessPath.FieldAccess (make_fieldname access_str)

Loading…
Cancel
Save