[infer][java] Create the procedure descriptions when required instead of creating them beforehand

Summary: This diff simplifies the workflow of creating the procedure descriptions. Instead of creating the all procedure descriptions in a first step and translating the method bodies afterwards, it is simpler to translate to do the two in one step.

Reviewed By: cristianoc

Differential Revision: D4067674

fbshipit-source-id: be9e853
master
Jeremy Dubreil 8 years ago committed by Facebook Github Bot
parent 471beed515
commit 219832a9a8

@ -75,12 +75,12 @@ let add_edges
(** Add a concrete method. *) (** Add a concrete method. *)
let add_cmethod source_file program icfg cm method_kind = let add_cmethod source_file program linereader icfg cm method_kind =
let cfg = icfg.JContext.cfg in
let cn, ms = JBasics.cms_split cm.Javalib.cm_class_method_signature in let cn, ms = JBasics.cms_split cm.Javalib.cm_class_method_signature in
let proc_name_java = JTransType.get_method_procname cn ms method_kind in let proc_name_java = JTransType.get_method_procname cn ms method_kind in
let proc_name = Procname.Java proc_name_java in let proc_name = Procname.Java proc_name_java in
match Cfg.Procdesc.find_from_name cfg proc_name with let jmethod = (Javalib.ConcreteMethod cm) in
match JTrans.create_procdesc source_file program linereader icfg jmethod with
| None -> () | None -> ()
| Some _ when JTrans.is_java_native cm -> () | Some _ when JTrans.is_java_native cm -> ()
| Some procdesc -> | Some procdesc ->
@ -101,15 +101,15 @@ let add_cmethod source_file program icfg cm method_kind =
(** Add an abstract method. *) (** Add an abstract method. *)
let add_amethod icfg am method_kind = let add_amethod source_file program linereader icfg am method_kind =
let cfg = icfg.JContext.cfg in
let cn, ms = JBasics.cms_split am.Javalib.am_class_method_signature in let cn, ms = JBasics.cms_split am.Javalib.am_class_method_signature in
let proc_name_java = JTransType.get_method_procname cn ms method_kind in let proc_name_java = JTransType.get_method_procname cn ms method_kind in
let proc_name = Procname.Java proc_name_java in let proc_name = Procname.Java proc_name_java in
match Cfg.Procdesc.find_from_name cfg proc_name with let jmethod = (Javalib.AbstractMethod am) in
match JTrans.create_procdesc source_file program linereader icfg jmethod with
| None -> () | None -> ()
| Some procdesc -> | Some _ ->
Cg.add_defined_node icfg.JContext.cg (Cfg.Procdesc.get_proc_name procdesc) Cg.add_defined_node icfg.JContext.cg proc_name
let path_of_cached_classname cn = let path_of_cached_classname cn =
@ -142,27 +142,23 @@ let cache_classname cn =
let is_classname_cached cn = let is_classname_cached cn =
Sys.file_exists (path_of_cached_classname cn) Sys.file_exists (path_of_cached_classname cn)
(* Given a source file and a class, translates the code of this class. (* 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 init - mode, finds out whether this class contains initializers at all,
in this case translates it. In standard mode, all methods are translated *) 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 icfg cn node =
JUtils.log "\tclassname: %s@." (JBasics.cn_name cn); JUtils.log "\tclassname: %s@." (JBasics.cn_name cn);
cache_classname cn; cache_classname cn;
let cfg = icfg.JContext.cfg in let translate m =
let tenv = icfg.JContext.tenv in (* each procedure has different scope: start names from id 0 *)
begin Ident.NameGenerator.reset ();
Javalib.m_iter (JTrans.create_procdesc source_file program linereader cfg tenv) node; let method_kind = JTransType.get_method_kind m in
Javalib.m_iter (fun m -> match m with
(* each procedure has different scope: start names from id 0 *) | Javalib.ConcreteMethod cm ->
Ident.NameGenerator.reset (); add_cmethod source_file program linereader icfg cm method_kind
let method_kind = JTransType.get_method_kind m in | Javalib.AbstractMethod am ->
match m with add_amethod source_file program linereader icfg am method_kind in
| Javalib.ConcreteMethod cm -> Javalib.m_iter translate node
add_cmethod source_file program icfg cm method_kind
| Javalib.AbstractMethod am ->
add_amethod icfg am method_kind
) node
end
(* returns true for the set of classes that are selected to be translated *) (* returns true for the set of classes that are selected to be translated *)

@ -202,10 +202,6 @@ let get_test_operator op =
| `Lt -> Binop.Lt | `Lt -> Binop.Lt
| `Ne -> Binop.Ne | `Ne -> Binop.Ne
type defined_status =
| Defined of Cfg.Procdesc.t
| Called of Cfg.Procdesc.t
let is_java_native cm = let is_java_native cm =
(cm.Javalib.cm_implementation = Javalib.Native) (cm.Javalib.cm_implementation = Javalib.Native)
@ -233,13 +229,18 @@ let update_init_loc cn ms loc_start =
with Not_found -> init_loc_map := (JBasics.ClassMap.add cn loc_start !init_loc_map) with Not_found -> init_loc_map := (JBasics.ClassMap.add cn loc_start !init_loc_map)
(** Creates a procedure description. *) (** Creates a procedure description. *)
let create_procdesc source_file program linereader cfg tenv m = let create_procdesc source_file program linereader icfg m : Cfg.Procdesc.t option =
let cfg = icfg.JContext.cfg in
let tenv = icfg.JContext.tenv in
let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in let cn, ms = JBasics.cms_split (Javalib.get_class_method_signature m) in
let proc_name_java = JTransType.get_method_procname cn ms (JTransType.get_method_kind m) in let proc_name_java = JTransType.get_method_procname cn ms (JTransType.get_method_kind m) in
let proc_name = Procname.Java proc_name_java in let proc_name = Procname.Java proc_name_java in
if JClasspath.is_model proc_name then if JClasspath.is_model proc_name then
(* do not translate the method if there is a model for it *) begin
JUtils.log "Skipping method with a model: %s@." (Procname.to_string proc_name) (* do not translate the method if there is a model for it *)
JUtils.log "Skipping method with a model: %s@." (Procname.to_string proc_name);
None
end
else else
let trans_access = function let trans_access = function
| `Default -> PredSymb.Default | `Default -> PredSymb.Default
@ -247,90 +248,96 @@ let create_procdesc source_file program linereader cfg tenv m =
| `Private -> PredSymb.Private | `Private -> PredSymb.Private
| `Protected -> PredSymb.Protected in | `Protected -> PredSymb.Protected in
try try
match m with let procdesc =
| Javalib.AbstractMethod am -> (* create a procdesc with empty body *) match m with
let formals = | Javalib.AbstractMethod am -> (* create a procdesc with empty body *)
formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in let formals =
let method_annotation = formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in
JAnnotation.translate_method proc_name_java am.Javalib.am_annotations in let method_annotation =
let procdesc = JAnnotation.translate_method proc_name_java am.Javalib.am_annotations in
let proc_attributes = let procdesc =
{ (ProcAttributes.default proc_name Config.Java) with let proc_attributes =
ProcAttributes.access = trans_access am.Javalib.am_access; { (ProcAttributes.default proc_name Config.Java) with
exceptions = IList.map JBasics.cn_name am.Javalib.am_exceptions; ProcAttributes.access = trans_access am.Javalib.am_access;
formals; exceptions = IList.map JBasics.cn_name am.Javalib.am_exceptions;
is_abstract = true; formals;
is_bridge_method = am.Javalib.am_bridge; is_abstract = true;
is_defined = true; is_bridge_method = am.Javalib.am_bridge;
is_synthetic_method = am.Javalib.am_synthetic; is_defined = true;
method_annotation; is_synthetic_method = am.Javalib.am_synthetic;
ret_type = JTransType.return_type program tenv ms; method_annotation;
} in ret_type = JTransType.return_type program tenv ms;
Cfg.Procdesc.create cfg proc_attributes in } in
let start_kind = Cfg.Node.Start_node procdesc in Cfg.Procdesc.create cfg proc_attributes in
let start_node = Cfg.Node.create cfg Location.dummy start_kind [] procdesc in let start_kind = Cfg.Node.Start_node procdesc in
let exit_kind = (Cfg.Node.Exit_node procdesc) in let start_node = Cfg.Node.create cfg Location.dummy start_kind [] procdesc in
let exit_node = Cfg.Node.create cfg Location.dummy exit_kind [] procdesc in let exit_kind = (Cfg.Node.Exit_node procdesc) in
Cfg.Node.set_succs_exn cfg start_node [exit_node] [exit_node]; let exit_node = Cfg.Node.create cfg Location.dummy exit_kind [] procdesc in
Cfg.Procdesc.set_start_node procdesc start_node; Cfg.Node.set_succs_exn cfg start_node [exit_node] [exit_node];
Cfg.Procdesc.set_exit_node procdesc exit_node Cfg.Procdesc.set_start_node procdesc start_node;
| Javalib.ConcreteMethod cm when is_java_native cm -> Cfg.Procdesc.set_exit_node procdesc exit_node;
let formals = formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in procdesc
let method_annotation = | Javalib.ConcreteMethod cm when is_java_native cm ->
JAnnotation.translate_method proc_name_java cm.Javalib.cm_annotations in let formals =
let proc_attributes = formals_from_signature program tenv cn ms (JTransType.get_method_kind m) in
{ (ProcAttributes.default proc_name Config.Java) with let method_annotation =
ProcAttributes.access = trans_access cm.Javalib.cm_access; JAnnotation.translate_method proc_name_java cm.Javalib.cm_annotations in
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
ignore (Cfg.Procdesc.create 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_java 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_java cm.Javalib.cm_annotations in
update_constr_loc cn ms loc_start;
update_init_loc cn ms loc_exit;
let procdesc =
let proc_attributes = let proc_attributes =
{ (ProcAttributes.default proc_name Config.Java) with { (ProcAttributes.default proc_name Config.Java) with
ProcAttributes.access = trans_access cm.Javalib.cm_access; ProcAttributes.access = trans_access cm.Javalib.cm_access;
exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions; exceptions = IList.map JBasics.cn_name cm.Javalib.cm_exceptions;
formals; formals;
is_bridge_method = cm.Javalib.cm_bridge; is_bridge_method = cm.Javalib.cm_bridge;
is_defined = true;
is_synthetic_method = cm.Javalib.cm_synthetic; is_synthetic_method = cm.Javalib.cm_synthetic;
is_java_synchronized_method = cm.Javalib.cm_synchronized;
loc = loc_start;
locals;
method_annotation; method_annotation;
ret_type = JTransType.return_type program tenv ms; ret_type = JTransType.return_type program tenv ms;
} in } in
Cfg.Procdesc.create cfg proc_attributes in Cfg.Procdesc.create cfg proc_attributes;
let start_kind = Cfg.Node.Start_node procdesc in | Javalib.ConcreteMethod cm ->
let start_node = Cfg.Node.create cfg loc_start start_kind [] procdesc in let impl = get_implementation cm in
let exit_kind = (Cfg.Node.Exit_node procdesc) in let locals, formals = locals_formals program tenv cn impl in
let exit_node = Cfg.Node.create cfg loc_exit exit_kind [] procdesc in let loc_start =
let exn_kind = Cfg.Node.exn_sink_kind in let loc = get_location source_file impl 0 in
let exn_node = Cfg.Node.create cfg loc_exit exn_kind [] procdesc in fix_method_definition_line linereader proc_name_java loc in
JContext.add_exn_node proc_name exn_node; let loc_exit =
Cfg.Procdesc.set_start_node procdesc start_node; get_location source_file impl (Array.length (JBir.code impl) - 1) in
Cfg.Procdesc.set_exit_node procdesc exit_node; let method_annotation =
Cfg.Node.add_locals_ret_declaration start_node locals; JAnnotation.translate_method proc_name_java cm.Javalib.cm_annotations in
update_constr_loc cn ms loc_start;
update_init_loc cn ms loc_exit;
let procdesc =
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
Cfg.Procdesc.create cfg proc_attributes in
let start_kind = Cfg.Node.Start_node procdesc in
let start_node = Cfg.Node.create cfg loc_start start_kind [] procdesc in
let exit_kind = (Cfg.Node.Exit_node procdesc) in
let exit_node = Cfg.Node.create cfg loc_exit exit_kind [] procdesc in
let exn_kind = Cfg.Node.exn_sink_kind in
let exn_node = Cfg.Node.create cfg loc_exit exn_kind [] procdesc 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 locals;
procdesc in
Some procdesc
with JBir.Subroutine | JBasics.Class_structure_error _ -> with JBir.Subroutine | JBasics.Class_structure_error _ ->
L.err L.stderr
"create_procdesc raised JBir.Subroutine or JBasics.Class_structure_error on %a@." "create_procdesc raised JBir.Subroutine or JBasics.Class_structure_error on %a@."
Procname.pp proc_name Procname.pp proc_name;
None
let builtin_new = let builtin_new =
Exp.Const (Const.Cfun ModelBuiltins.__new) Exp.Const (Const.Cfun ModelBuiltins.__new)

@ -20,11 +20,6 @@ type translation =
| Prune of Cfg.Node.t * Cfg.Node.t | Prune of Cfg.Node.t * Cfg.Node.t
| Loop of Cfg.Node.t * Cfg.Node.t * Cfg.Node.t | Loop of Cfg.Node.t * Cfg.Node.t * Cfg.Node.t
(** data structure to identify whether a method is defined in the given program *)
type defined_status =
| Defined of Cfg.Procdesc.t
| Called of Cfg.Procdesc.t
val is_java_native : JCode.jcode Javalib.concrete_method -> bool val is_java_native : JCode.jcode Javalib.concrete_method -> bool
(** [create_procdesc linereader cfg tenv program m] creates a procedure description (** [create_procdesc linereader cfg tenv program m] creates a procedure description
@ -33,10 +28,9 @@ val create_procdesc :
DB.source_file -> DB.source_file ->
JClasspath.program -> JClasspath.program ->
Printer.LineReader.t -> Printer.LineReader.t ->
Cfg.cfg -> JContext.icfg ->
Tenv.t ->
JCode.jcode Javalib.jmethod -> JCode.jcode Javalib.jmethod ->
unit Cfg.Procdesc.t option
(** returns the implementation of a given method *) (** returns the implementation of a given method *)
val get_implementation : JCode.jcode Javalib.concrete_method -> JBir.t val get_implementation : JCode.jcode Javalib.concrete_method -> JBir.t

Loading…
Cancel
Save