diff --git a/infer/src/java/jFrontend.ml b/infer/src/java/jFrontend.ml index feb9e2caf..c58647576 100644 --- a/infer/src/java/jFrontend.ml +++ b/infer/src/java/jFrontend.ml @@ -77,11 +77,9 @@ let add_edges (** Add a concrete method. *) let add_cmethod source_file program linereader icfg cm proc_name = let cn, _ = JBasics.cms_split cm.Javalib.cm_class_method_signature in - let jmethod = (Javalib.ConcreteMethod cm) in - match JTrans.create_procdesc source_file program linereader icfg jmethod with + match JTrans.create_cm_procdesc source_file program linereader icfg cm proc_name with | None -> () - | Some _ when JTrans.is_java_native cm -> () - | Some procdesc -> + | Some (procdesc, impl) -> let start_node = Cfg.Procdesc.get_start_node procdesc in let exit_node = Cfg.Procdesc.get_exit_node procdesc in let exn_node = @@ -89,7 +87,6 @@ let add_cmethod source_file program linereader icfg cm proc_name = | Some node -> node | None -> failwithf "No exn node found for %s" (Procname.to_string proc_name) in - let impl = JTrans.get_implementation cm in let instrs = JBir.code impl in let context = JContext.create_context icfg procdesc impl cn source_file program in @@ -98,15 +95,6 @@ let add_cmethod source_file program linereader icfg cm proc_name = Cg.add_defined_node icfg.JContext.cg proc_name -(** Add an abstract method. *) -let add_amethod source_file program linereader icfg am proc_name = - let jmethod = (Javalib.AbstractMethod am) in - match JTrans.create_procdesc source_file program linereader icfg jmethod with - | None -> () - | Some _ -> - Cg.add_defined_node icfg.JContext.cg proc_name - - let path_of_cached_classname cn = let root_path = Filename.concat Config.results_dir "classnames" in let package_path = IList.fold_left Filename.concat root_path (JBasics.cn_package cn) in @@ -151,15 +139,22 @@ let create_icfg source_file linereader program icfg cn node = (* do not translate the method if there is a model for it *) L.out_debug "Skipping method with a model: %s@." (Procname.to_string proc_name) else - begin + try (* each procedure has different scope: start names from id 0 *) Ident.NameGenerator.reset (); match m with + | Javalib.AbstractMethod am -> + ignore (JTrans.create_am_procdesc program icfg am proc_name); + (* TODO #4040807: investigate why we need to mark asbtract methods as defined *) + Cg.add_defined_node icfg.JContext.cg proc_name + | Javalib.ConcreteMethod cm when JTrans.is_java_native cm -> + ignore (JTrans.create_native_procdesc program icfg cm proc_name) | Javalib.ConcreteMethod cm -> add_cmethod source_file program linereader icfg cm proc_name - | Javalib.AbstractMethod am -> - add_amethod source_file program linereader icfg am proc_name - end in + with JBasics.Class_structure_error _ -> + L.do_err + "create_icfg raised JBasics.Class_structure_error on %a@." + Procname.pp proc_name in Javalib.m_iter translate node diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index 441984cb2..4f46fb58e 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -230,106 +230,115 @@ let update_init_loc cn ms loc_start = try ignore(JBasics.ClassMap.find cn !init_loc_map) with Not_found -> init_loc_map := (JBasics.ClassMap.add cn loc_start !init_loc_map) +let trans_access = function + | `Default -> PredSymb.Default + | `Public -> PredSymb.Public + | `Private -> PredSymb.Private + | `Protected -> PredSymb.Protected + +let create_am_procdesc program icfg am proc_name : Cfg.Procdesc.t = + let cfg = icfg.JContext.cfg in + let tenv = icfg.JContext.tenv in + let m = Javalib.AbstractMethod am in + let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in + let formals = + formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in + let method_annotation = + JAnnotation.translate_method proc_name am.Javalib.am_annotations in + let procdesc = + let proc_attributes = + { (ProcAttributes.default proc_name Config.Java) with + ProcAttributes.access = trans_access am.Javalib.am_access; + exceptions = IList.map JBasics.cn_name am.Javalib.am_exceptions; + formals; + is_abstract = true; + is_bridge_method = am.Javalib.am_bridge; + is_defined = true; + is_synthetic_method = am.Javalib.am_synthetic; + method_annotation; + ret_type = JTransType.return_type program tenv ms; + } in + Cfg.create_proc_desc cfg proc_attributes in + let start_kind = Cfg.Node.Start_node proc_name in + let start_node = Cfg.Procdesc.create_node procdesc Location.dummy start_kind [] in + let exit_kind = (Cfg.Node.Exit_node proc_name) in + let exit_node = Cfg.Procdesc.create_node procdesc Location.dummy exit_kind [] in + Cfg.Procdesc.node_set_succs_exn procdesc start_node [exit_node] [exit_node]; + Cfg.Procdesc.set_start_node procdesc start_node; + Cfg.Procdesc.set_exit_node procdesc exit_node; + procdesc + +let create_native_procdesc program icfg cm proc_name = + let cfg = icfg.JContext.cfg in + let tenv = icfg.JContext.tenv in + let m = Javalib.ConcreteMethod cm in + let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in + let formals = + formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in + let method_annotation = + JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in + let proc_attributes = + { (ProcAttributes.default proc_name Config.Java) with + ProcAttributes.access = trans_access cm.Javalib.cm_access; + exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; + formals; + is_bridge_method = cm.Javalib.cm_bridge; + is_synthetic_method = cm.Javalib.cm_synthetic; + method_annotation; + ret_type = JTransType.return_type program tenv ms; + } in + Cfg.create_proc_desc cfg proc_attributes + (** Creates a procedure description. *) -let create_procdesc source_file program linereader icfg m : Cfg.Procdesc.t option = +let create_cm_procdesc source_file program linereader icfg cm proc_name = let cfg = icfg.JContext.cfg in let tenv = icfg.JContext.tenv in + let m = Javalib.ConcreteMethod cm in let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in - let proc_name = JTransType.translate_method_name m in - let trans_access = function - | `Default -> PredSymb.Default - | `Public -> PredSymb.Public - | `Private -> PredSymb.Private - | `Protected -> PredSymb.Protected in try + let impl = get_implementation cm in let procdesc = - match m with - | Javalib.AbstractMethod am -> (* create a procdesc with empty body *) - let formals = - formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in - let method_annotation = - JAnnotation.translate_method proc_name am.Javalib.am_annotations in - let procdesc = - let proc_attributes = - { (ProcAttributes.default proc_name Config.Java) with - ProcAttributes.access = trans_access am.Javalib.am_access; - exceptions = IList.map JBasics.cn_name am.Javalib.am_exceptions; - formals; - is_abstract = true; - is_bridge_method = am.Javalib.am_bridge; - is_defined = true; - is_synthetic_method = am.Javalib.am_synthetic; - method_annotation; - ret_type = JTransType.return_type program tenv ms; - } in - Cfg.create_proc_desc cfg proc_attributes in - let start_kind = Cfg.Node.Start_node proc_name in - let start_node = Cfg.Procdesc.create_node procdesc Location.dummy start_kind [] in - let exit_kind = (Cfg.Node.Exit_node proc_name) in - let exit_node = Cfg.Procdesc.create_node procdesc Location.dummy exit_kind [] in - Cfg.Procdesc.node_set_succs_exn procdesc start_node [exit_node] [exit_node]; - Cfg.Procdesc.set_start_node procdesc start_node; - Cfg.Procdesc.set_exit_node procdesc exit_node; - procdesc - | Javalib.ConcreteMethod cm when is_java_native cm -> - let formals = - formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in - let method_annotation = - JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in - let proc_attributes = - { (ProcAttributes.default proc_name Config.Java) with - ProcAttributes.access = trans_access cm.Javalib.cm_access; - exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; - formals; - is_bridge_method = cm.Javalib.cm_bridge; - is_synthetic_method = cm.Javalib.cm_synthetic; - method_annotation; - ret_type = JTransType.return_type program tenv ms; - } in - Cfg.create_proc_desc cfg proc_attributes; - | Javalib.ConcreteMethod cm -> - let impl = get_implementation cm in - let locals, formals = locals_formals program tenv cn impl in - let loc_start = - let loc = get_location source_file impl 0 in - fix_method_definition_line linereader proc_name loc in - let loc_exit = - get_location source_file impl (Array.length (JBir.code impl) - 1) in - let method_annotation = - JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in - update_constr_loc cn ms loc_start; - update_init_loc cn ms loc_exit; - let proc_attributes = - { (ProcAttributes.default proc_name Config.Java) with - ProcAttributes.access = trans_access cm.Javalib.cm_access; - exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; - formals; - is_bridge_method = cm.Javalib.cm_bridge; - is_defined = true; - is_synthetic_method = cm.Javalib.cm_synthetic; - is_java_synchronized_method = cm.Javalib.cm_synchronized; - loc = loc_start; - locals; - method_annotation; - ret_type = JTransType.return_type program tenv ms; - } in - let procdesc = - Cfg.create_proc_desc cfg proc_attributes in - let start_kind = Cfg.Node.Start_node proc_name in - let start_node = Cfg.Procdesc.create_node procdesc loc_start start_kind [] in - let exit_kind = (Cfg.Node.Exit_node proc_name) in - let exit_node = Cfg.Procdesc.create_node procdesc loc_exit exit_kind [] in - let exn_kind = Cfg.Node.exn_sink_kind in - let exn_node = Cfg.Procdesc.create_node procdesc loc_exit exn_kind [] in - JContext.add_exn_node proc_name exn_node; - Cfg.Procdesc.set_start_node procdesc start_node; - Cfg.Procdesc.set_exit_node procdesc exit_node; - Cfg.Node.add_locals_ret_declaration start_node proc_attributes locals; - procdesc in - Some procdesc - with JBir.Subroutine | JBasics.Class_structure_error _ -> + let locals, formals = locals_formals program tenv cn impl in + let loc_start = + let loc = get_location source_file impl 0 in + fix_method_definition_line linereader proc_name loc in + let loc_exit = + get_location source_file impl (Array.length (JBir.code impl) - 1) in + let method_annotation = + JAnnotation.translate_method proc_name cm.Javalib.cm_annotations in + update_constr_loc cn ms loc_start; + update_init_loc cn ms loc_exit; + let proc_attributes = + { (ProcAttributes.default proc_name Config.Java) with + ProcAttributes.access = trans_access cm.Javalib.cm_access; + exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; + formals; + is_bridge_method = cm.Javalib.cm_bridge; + is_defined = true; + is_synthetic_method = cm.Javalib.cm_synthetic; + is_java_synchronized_method = cm.Javalib.cm_synchronized; + loc = loc_start; + locals; + method_annotation; + ret_type = JTransType.return_type program tenv ms; + } in + let procdesc = + Cfg.create_proc_desc cfg proc_attributes in + let start_kind = Cfg.Node.Start_node proc_name in + let start_node = Cfg.Procdesc.create_node procdesc loc_start start_kind [] in + let exit_kind = (Cfg.Node.Exit_node proc_name) in + let exit_node = Cfg.Procdesc.create_node procdesc loc_exit exit_kind [] in + let exn_kind = Cfg.Node.exn_sink_kind in + let exn_node = Cfg.Procdesc.create_node procdesc loc_exit exn_kind [] in + JContext.add_exn_node proc_name exn_node; + Cfg.Procdesc.set_start_node procdesc start_node; + Cfg.Procdesc.set_exit_node procdesc exit_node; + Cfg.Node.add_locals_ret_declaration start_node proc_attributes locals; + procdesc in + Some (procdesc, impl) + with JBir.Subroutine -> L.do_err - "create_procdesc raised JBir.Subroutine or JBasics.Class_structure_error on %a@." + "create_procdesc raised JBir.Subroutine on %a@." Procname.pp proc_name; None diff --git a/infer/src/java/jTrans.mli b/infer/src/java/jTrans.mli index 7eca6ad86..bfc4867aa 100644 --- a/infer/src/java/jTrans.mli +++ b/infer/src/java/jTrans.mli @@ -22,18 +22,28 @@ type translation = val is_java_native : JCode.jcode Javalib.concrete_method -> bool -(** [create_procdesc linereader cfg tenv program m] creates a procedure description - for the method m and adds it to cfg *) -val create_procdesc : +(** Create the procedure description for an abstract method *) +val create_am_procdesc : + JClasspath.program -> JContext.icfg -> Javalib.abstract_method -> Procname.t -> Cfg.Procdesc.t + +(** Create the procedure description for a concrete method *) +val create_native_procdesc : + JClasspath.program -> + JContext.icfg -> + JCode.jcode Javalib.concrete_method -> + Procname.t -> + Cfg.Procdesc.t + +(** [create_procdesc source_file program linereader icfg cm proc_name] creates + a procedure description for the concrete method cm and adds it to cfg *) +val create_cm_procdesc : DB.source_file -> JClasspath.program -> Printer.LineReader.t -> JContext.icfg -> - JCode.jcode Javalib.jmethod -> - Cfg.Procdesc.t option - -(** returns the implementation of a given method *) -val get_implementation : JCode.jcode Javalib.concrete_method -> JBir.t + JCode.jcode Javalib.concrete_method -> + Procname.t -> + (Cfg.Procdesc.t * JBir.t) option (** translates an instruction into a statement node or prune nodes in the cfg *) val instruction : JContext.t -> int -> JBir.instr -> translation