From ad8c5d68a2a30d6f9685636c83f93b68583416c3 Mon Sep 17 00:00:00 2001 From: Jeremy Dubreil Date: Mon, 30 Jul 2018 15:07:34 -0700 Subject: [PATCH] [infer][java] make sure the type definition of the class always exists in the type environment when translating one of its method Summary: This avoid cases where the type definition is not found when trying to lookup the type definition for the class starting from the method name. Reviewed By: ngorogiannis Differential Revision: D9027983 fbshipit-source-id: 1add7692f --- infer/src/java/jFrontend.ml | 8 +-- infer/src/java/jTrans.ml | 2 +- infer/src/java/jTransType.ml | 128 +++++++++++++++++++--------------- infer/src/java/jTransType.mli | 6 +- 4 files changed, 79 insertions(+), 65 deletions(-) diff --git a/infer/src/java/jFrontend.ml b/infer/src/java/jFrontend.ml index 3ee33daf2..00943f94b 100644 --- a/infer/src/java/jFrontend.ml +++ b/infer/src/java/jFrontend.ml @@ -134,11 +134,11 @@ let is_classname_cached cn = Sys.file_exists (path_of_cached_classname cn) = `Ye (* Given a source file and a class, translates the code of this class. In init - mode, finds out whether this class contains initializers at all, in this case translates it. In standard mode, all methods are translated *) -let create_icfg source_file linereader program icfg cn node = +let create_icfg source_file linereader program tenv icfg cn node = L.(debug Capture Verbose) "\tclassname: %s@." (JBasics.cn_name cn) ; if Config.dependency_mode && not (is_classname_cached cn) then cache_classname cn ; let translate m = - let proc_name = JTransType.translate_method_name m in + let proc_name = JTransType.translate_method_name program tenv m in JClasspath.set_callee_translated program proc_name ; if JClasspath.is_model proc_name then (* do not translate the method if there is a model for it *) @@ -198,7 +198,7 @@ let compute_source_icfg linereader classes program tenv source_basename package_ JBasics.ClassMap.iter (select (should_capture classes package_opt source_basename) - (create_icfg source_file linereader program icfg)) + (create_icfg source_file linereader program tenv icfg)) (JClasspath.get_classmap program) in icfg.JContext.cfg @@ -206,6 +206,6 @@ let compute_source_icfg linereader classes program tenv source_basename package_ let compute_class_icfg source_file linereader program tenv node = let icfg = {JContext.cfg= Cfg.create (); tenv} in - ( try create_icfg source_file linereader program icfg (Javalib.get_name node) node + ( try create_icfg source_file linereader program tenv icfg (Javalib.get_name node) node with Bir.Subroutine -> () ) ; icfg.JContext.cfg diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 7e8f36312..2337cc53c 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -651,7 +651,7 @@ let method_invocation (context: JContext.t) loc pc var_opt cn ms sil_obj_opt exp JBasics.cn_equal cn' (JBasics.make_cn JConfig.infer_builtins_cl) && BuiltinDecl.is_declared proc then proc - else JTransType.get_method_procname cn' ms method_kind + else JTransType.get_method_procname program tenv cn' ms method_kind in JClasspath.add_missing_callee program callee_procname cn' ms ; let call_instrs = diff --git a/infer/src/java/jTransType.ml b/infer/src/java/jTransType.ml index b643299ff..3fafaa74a 100644 --- a/infer/src/java/jTransType.ml +++ b/infer/src/java/jTransType.ml @@ -216,21 +216,6 @@ let get_method_kind m = if Javalib.is_static_method m then Typ.Procname.Java.Static else Typ.Procname.Java.Non_Static -let get_method_procname cn ms method_kind = - let return_type_name, method_name, args_type_name = method_signature_names ms in - let class_name = Typ.Name.Java.from_string (JBasics.cn_name cn) in - let proc_name_java = - Typ.Procname.Java.make class_name return_type_name method_name args_type_name method_kind - in - Typ.Procname.Java proc_name_java - - -(* create a mangled procname from an abstract or concrete method *) -let translate_method_name m = - let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in - get_method_procname cn ms (get_method_kind m) - - let fieldname_create cn fs = let fieldname = JBasics.fs_name fs in let classname = JBasics.cn_name cn in @@ -310,7 +295,23 @@ let add_model_fields program classpath_fields cn = with Caml.Not_found -> classpath_fields -let rec get_all_fields program tenv cn = +let rec get_method_procname program tenv cn ms method_kind = + let _ : Typ.Struct.t = get_class_struct_typ program tenv cn in + let return_type_name, method_name, args_type_name = method_signature_names ms in + let class_name = Typ.Name.Java.from_string (JBasics.cn_name cn) in + let proc_name_java = + Typ.Procname.Java.make class_name return_type_name method_name args_type_name method_kind + in + Typ.Procname.Java proc_name_java + + +(* create a mangled procname from an abstract or concrete method *) +and translate_method_name program tenv m = + let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in + get_method_procname program tenv cn ms (get_method_kind m) + + +and get_all_fields program tenv cn = let extract_class_fields classname = let {Typ.Struct.fields; statics} = get_class_struct_typ program tenv classname in (statics, fields) @@ -346,49 +347,60 @@ let rec get_all_fields program tenv cn = trans_fields cn -and get_class_struct_typ program tenv cn = - let name = typename_of_classname cn in - match Tenv.lookup tenv name with - | Some struct_typ -> - struct_typ - | None -> - match JClasspath.lookup_node cn program with - | None -> +and get_class_struct_typ = + let seen = ref JBasics.ClassSet.empty in + fun program tenv cn -> + let name = typename_of_classname cn in + match Tenv.lookup tenv name with + | Some struct_typ -> + struct_typ + | None when JBasics.ClassSet.mem cn !seen -> Tenv.mk_struct tenv name - | Some node -> - let create_super_list interface_names = - List.iter ~f:(fun cn -> ignore (get_class_struct_typ program tenv cn)) interface_names ; - List.map ~f:typename_of_classname interface_names - in - let supers, fields, statics, annots = - match node with - | Javalib.JInterface jinterface -> - let statics, _ = get_all_fields program tenv cn in - let sil_interface_list = create_super_list jinterface.Javalib.i_interfaces in - let item_annotation = JAnnotation.translate_item jinterface.Javalib.i_annotations in - (sil_interface_list, [], statics, item_annotation) - | Javalib.JClass jclass -> - let statics, nonstatics = - let classpath_static, classpath_nonstatic = get_all_fields program tenv cn in - add_model_fields program (classpath_static, classpath_nonstatic) cn - in - let item_annotation = JAnnotation.translate_item jclass.Javalib.c_annotations in - let interface_list = create_super_list jclass.Javalib.c_interfaces in - let super_classname_list = - match jclass.Javalib.c_super_class with - | None -> - interface_list (* base case of the recursion *) - | Some super_cn -> - ignore (get_class_struct_typ program tenv super_cn) ; - let super_classname = typename_of_classname super_cn in - super_classname :: interface_list - in - (super_classname_list, nonstatics, statics, item_annotation) - in - let methods = - Javalib.m_fold (fun m procnames -> translate_method_name m :: procnames) node [] - in - Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots name + | None -> + seen := JBasics.ClassSet.add cn !seen ; + match JClasspath.lookup_node cn program with + | None -> + Tenv.mk_struct tenv name + | Some node -> + let create_super_list interface_names = + List.iter + ~f:(fun cn -> ignore (get_class_struct_typ program tenv cn)) + interface_names ; + List.map ~f:typename_of_classname interface_names + in + let supers, fields, statics, annots = + match node with + | Javalib.JInterface jinterface -> + let statics, _ = get_all_fields program tenv cn in + let sil_interface_list = create_super_list jinterface.Javalib.i_interfaces in + let item_annotation = + JAnnotation.translate_item jinterface.Javalib.i_annotations + in + (sil_interface_list, [], statics, item_annotation) + | Javalib.JClass jclass -> + let statics, nonstatics = + let classpath_static, classpath_nonstatic = get_all_fields program tenv cn in + add_model_fields program (classpath_static, classpath_nonstatic) cn + in + let item_annotation = JAnnotation.translate_item jclass.Javalib.c_annotations in + let interface_list = create_super_list jclass.Javalib.c_interfaces in + let super_classname_list = + match jclass.Javalib.c_super_class with + | None -> + interface_list (* base case of the recursion *) + | Some super_cn -> + ignore (get_class_struct_typ program tenv super_cn) ; + let super_classname = typename_of_classname super_cn in + super_classname :: interface_list + in + (super_classname_list, nonstatics, statics, item_annotation) + in + let methods = + Javalib.m_fold + (fun m procnames -> translate_method_name program tenv m :: procnames) + node [] + in + Tenv.mk_struct tenv ~fields ~statics ~methods ~supers ~annots name let get_class_type_no_pointer program tenv cn = diff --git a/infer/src/java/jTransType.mli b/infer/src/java/jTransType.mli index 39b1b8eab..bb5686525 100644 --- a/infer/src/java/jTransType.mli +++ b/infer/src/java/jTransType.mli @@ -13,10 +13,12 @@ open Sawja_pack val get_method_kind : JCode.jcode Javalib.jmethod -> Typ.Procname.Java.kind val get_method_procname : - JBasics.class_name -> JBasics.method_signature -> Typ.Procname.Java.kind -> Typ.Procname.t + JClasspath.program -> Tenv.t -> JBasics.class_name -> JBasics.method_signature + -> Typ.Procname.Java.kind -> Typ.Procname.t (** returns a procedure name based on the class name and the method's signature. *) -val translate_method_name : JCode.jcode Javalib.jmethod -> Typ.Procname.t +val translate_method_name : + JClasspath.program -> Tenv.t -> JCode.jcode Javalib.jmethod -> Typ.Procname.t (** translate the SIL procedure name of the Java method *) val get_class_struct_typ : JClasspath.program -> Tenv.t -> JBasics.class_name -> Typ.Struct.t