From 2f57b094e9fadd7f2731191c7959f150190d79b2 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Wed, 11 Apr 2018 08:37:43 -0700 Subject: [PATCH] Java split name as an abstract type Reviewed By: sblackshear Differential Revision: D7291611 fbshipit-source-id: 0c15ecd --- infer/src/IR/Typ.ml | 70 ++++++++++++++++++++------------ infer/src/IR/Typ.mli | 21 +++++++--- infer/src/biabduction/SymExec.ml | 4 +- infer/src/eradicate/typeCheck.ml | 4 +- infer/src/java/jTransType.ml | 12 ++++-- 5 files changed, 70 insertions(+), 41 deletions(-) diff --git a/infer/src/IR/Typ.ml b/infer/src/IR/Typ.ml index 17669a059..12187ac9e 100644 --- a/infer/src/IR/Typ.ml +++ b/infer/src/IR/Typ.ml @@ -388,6 +388,33 @@ module Name = struct end module Java = struct + module Split = struct + (** e.g. {type_name="int"; package=None} for primitive types + * or {type_name="PrintWriter"; package=Some "java.io"} for objects. + *) + type t = {package: string option; type_name: string} + + let make ?package type_name = {type_name; package} + + (** Given a package.class_name string, it looks for the latest dot and split the string + in two (package, class_name) *) + let of_string package_classname = + match String.rsplit2 package_classname ~on:'.' with + | Some (package, type_name) -> + {type_name; package= Some package} + | None -> + {type_name= package_classname; package= None} + + + let package {package} = package + + let type_name {type_name} = type_name + + let java_lang_object = make ~package:"java.lang" "Object" + + let java_lang_string = make ~package:"java.lang" "String" + end + let from_string name_str = JavaClass (Mangled.from_string name_str) let from_package_class package_name class_name = @@ -403,29 +430,19 @@ module Name = struct let java_lang_cloneable = from_string "java.lang.Cloneable" - (** Given a package.class_name string, it looks for the latest dot and split the string - in two (package, class_name) *) - let split_classname package_classname = - match String.rsplit2 package_classname ~on:'.' with - | Some (x, y) -> - (Some x, y) - | None -> - (None, package_classname) - - - let split_typename typename = split_classname (name typename) + let split_typename typename = Split.of_string (name typename) let get_outer_class class_name = - let package_name, class_name_no_package = split_typename class_name in - match String.rsplit2 ~on:'$' class_name_no_package with + let {Split.package; type_name} = split_typename class_name in + match String.rsplit2 ~on:'$' type_name with | Some (parent_class, _) -> - Some (from_package_class (Option.value ~default:"" package_name) parent_class) + Some (from_package_class (Option.value ~default:"" package) parent_class) | None -> None let is_anonymous_inner_class_name class_name = - let class_name_no_package = snd (split_typename class_name) in + let class_name_no_package = Split.type_name (split_typename class_name) in match String.rsplit2 class_name_no_package ~on:'$' with | Some (_, s) -> let is_int = @@ -440,7 +457,7 @@ module Name = struct let is_external_classname name_string = - let package, _ = split_classname name_string in + let {Split.package} = Split.of_string name_string in Option.exists ~f:Config.java_package_is_external package @@ -541,10 +558,9 @@ module Procname = struct [@@deriving compare] (* TODO: use Mangled.t here *) - type java_type = string option * string - - (* compare in inverse order *) - let compare_java_type (p1, c1) (p2, c2) = [%compare : string * string option] (c1, p1) (c2, p2) + type java_type = Name.Java.Split.t = + {package: string option; type_name: string} + [@@deriving compare] (** Type of java procedure names. *) type t = @@ -562,10 +578,10 @@ module Procname = struct (** A type is a pair (package, type_name) that is translated in a string package.type_name *) let type_to_string_verbosity p verbosity = match p with - | None, typ -> - typ - | Some p, cls -> - if is_verbose verbosity then p ^ "." ^ cls else cls + | {package= Some package; type_name} when is_verbose verbosity -> + package ^ "." ^ type_name + | {type_name} -> + type_name (** Given a list of types, it creates a unique string of types separated by commas *) @@ -589,9 +605,9 @@ module Procname = struct let get_class_type_name j = j.class_name - let get_simple_class_name j = snd (Name.Java.split_classname (get_class_name j)) + let get_simple_class_name j = Name.Java.Split.(j |> get_class_name |> of_string |> type_name) - let get_package j = fst (Name.Java.split_classname (get_class_name j)) + let get_package j = Name.Java.Split.(j |> get_class_name |> of_string |> package) let get_method j = j.method_name @@ -707,7 +723,7 @@ module Procname = struct (** Check if the proc name has the type of a java vararg. Note: currently only checks that the last argument has type Object[]. *) let is_vararg {parameters} = - match List.last parameters with Some (_, "java.lang.Object[]") -> true | _ -> false + match List.last parameters with Some {type_name= "java.lang.Object[]"} -> true | _ -> false let is_external java_pname = diff --git a/infer/src/IR/Typ.mli b/infer/src/IR/Typ.mli index 854ab4202..f2030cc7b 100644 --- a/infer/src/IR/Typ.mli +++ b/infer/src/IR/Typ.mli @@ -153,6 +153,20 @@ module Name : sig end module Java : sig + module Split : sig + type t + + val make : ?package:string -> string -> t + + val of_string : string -> t + (** Given a package.class_name string, look for the latest dot and split the string + in two (package, class_name). *) + + val java_lang_object : t + + val java_lang_string : t + end + val from_string : string -> t (** Create a typename from a Java classname in the form "package.class" *) @@ -168,10 +182,6 @@ module Name : sig val is_external : t -> bool (** return true if the typename is in the .inferconfig list of external classes *) - val split_classname : string -> string option * string - (** Given a package.class_name string, look for the latest dot and split the string - in two (package, class_name). *) - val get_outer_class : t -> t option (** Given an inner classname like C$Inner1$Inner2, return Some C$Inner1. If the class is not an inner class, return None *) @@ -279,8 +289,7 @@ module Procname : sig type t [@@deriving compare] - (** e.g. ("", "int") for primitive types or ("java.io", "PrintWriter") for objects *) - type java_type = string option * string + type java_type = Name.Java.Split.t val make : Name.t -> java_type option -> string -> java_type list -> kind -> t (** Create a Java procedure name from its diff --git a/infer/src/biabduction/SymExec.ml b/infer/src/biabduction/SymExec.ml index ad106df65..a10bf10a4 100644 --- a/infer/src/biabduction/SymExec.ml +++ b/infer/src/biabduction/SymExec.ml @@ -612,7 +612,7 @@ let resolve_java_pname tenv prop args pname_java call_flags : Typ.Procname.Java. ~f:(fun accu (arg_exp, _) name -> match resolve_typename prop arg_exp with | Some class_name -> - Typ.Name.Java.split_classname (Typ.Name.name class_name) :: accu + Typ.Name.Java.Split.of_string (Typ.Name.name class_name) :: accu | None -> name :: accu ) ~init:[] args @@ -695,7 +695,7 @@ let call_constructor_url_update_args pname actual_params = Typ.Procname.Java (Typ.Procname.Java.make (Typ.Name.Java.from_string "java.net.URL") - None "" [(Some "java.lang", "String")] Typ.Procname.Java.Non_Static) + None "" [Typ.Name.Java.Split.java_lang_string] Typ.Procname.Java.Non_Static) in if Typ.Procname.equal url_pname pname then match actual_params with diff --git a/infer/src/eradicate/typeCheck.ml b/infer/src/eradicate/typeCheck.ml index 7f4223f37..d6f4b465d 100644 --- a/infer/src/eradicate/typeCheck.ml +++ b/infer/src/eradicate/typeCheck.ml @@ -705,7 +705,7 @@ let typecheck_instr tenv ext calls_this checks (node: Procdesc.Node.t) idenv get let do_map_put typestate' = (* Get the proc name for map.get() from map.put() *) let pname_get_from_pname_put pname_put = - let object_t = (Some "java.lang", "Object") in + let object_t = Typ.Name.Java.Split.java_lang_object in let parameters = [object_t] in pname_put |> Typ.Procname.Java.replace_method_name "get" |> Typ.Procname.Java.replace_return_type object_t @@ -904,7 +904,7 @@ let typecheck_instr tenv ext calls_this checks (node: Procdesc.Node.t) idenv get DExp.Dretcall (DExp.Dconst Const.Cfun Typ.Procname.Java pname_java, args, loc, call_flags) -> let pname_java' = - let object_t = (Some "java.lang", "Object") in + let object_t = Typ.Name.Java.Split.java_lang_object in pname_java |> Typ.Procname.Java.replace_method_name "get" |> Typ.Procname.Java.replace_return_type object_t in diff --git a/infer/src/java/jTransType.ml b/infer/src/java/jTransType.ml index 4697f8654..ed2c783cc 100644 --- a/infer/src/java/jTransType.ml +++ b/infer/src/java/jTransType.ml @@ -182,16 +182,20 @@ let rec string_of_type vt = let package_to_string = function [] -> None | p -> Some (String.concat ~sep:"." p) -let cn_to_java_type cn = (package_to_string (JBasics.cn_package cn), JBasics.cn_simple_name cn) +let cn_to_java_type cn = + Typ.Name.Java.Split.make + ?package:(package_to_string (JBasics.cn_package cn)) + (JBasics.cn_simple_name cn) + let vt_to_java_type vt = match vt with | JBasics.TBasic bt -> - (None, string_of_basic_type bt) + Typ.Name.Java.Split.make (string_of_basic_type bt) | JBasics.TObject ot -> match ot with | JBasics.TArray vt -> - (None, string_of_type vt ^ "[]") + Typ.Name.Java.Split.make (string_of_type vt ^ "[]") | JBasics.TClass cn -> cn_to_java_type cn @@ -201,7 +205,7 @@ let method_signature_names ms = match JBasics.ms_rtype ms with | None -> if String.equal (JBasics.ms_name ms) JConfig.constructor_name then None - else Some (None, JConfig.void) + else Some (Typ.Name.Java.Split.make JConfig.void) | Some vt -> Some (vt_to_java_type vt) in