[cfg] rename `Cfg.is_proc_cfg_connected` to `Procdesc.is_connected`

Summary: Moving this function since it's about a single procdesc. Slight rewrite too.

Reviewed By: da319

Differential Revision: D8030494

fbshipit-source-id: f7cc58e
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 818d359675
commit 92c129dc4e

@ -53,71 +53,6 @@ let iter_all_nodes ?(sorted= false) cfg ~f =
|> List.iter ~f:(fun (_, d, n) -> f d n) |> List.iter ~f:(fun (_, d, n) -> f d n)
let proc_cfg_broken_for_node proc_desc =
let is_exit_node n =
match Procdesc.Node.get_kind n with Procdesc.Node.Exit_node _ -> true | _ -> false
in
let is_between_join_and_exit_node n =
match Procdesc.Node.get_kind n with
| Procdesc.Node.Stmt_node "between_join_and_exit" | Procdesc.Node.Stmt_node "Destruction" -> (
match Procdesc.Node.get_succs n with [n'] when is_exit_node n' -> true | _ -> false )
| _ ->
false
in
let rec is_consecutive_join_nodes n visited =
match Procdesc.Node.get_kind n with
| Procdesc.Node.Join_node
-> (
if Procdesc.NodeSet.mem n visited then false
else
let succs = Procdesc.Node.get_succs n in
match succs with
| [n'] ->
is_consecutive_join_nodes n' (Procdesc.NodeSet.add n visited)
| _ ->
false )
| _ ->
is_between_join_and_exit_node n
in
let find_broken_node n =
let succs = Procdesc.Node.get_succs n in
let preds = Procdesc.Node.get_preds n in
match Procdesc.Node.get_kind n with
| Procdesc.Node.Start_node _ ->
if List.is_empty succs || not (List.is_empty preds) then Some `Other else None
| Procdesc.Node.Exit_node _ ->
if not (List.is_empty succs) || List.is_empty preds then Some `Other else None
| Procdesc.Node.Stmt_node _ | Procdesc.Node.Prune_node _ | Procdesc.Node.Skip_node _ ->
if List.is_empty succs || List.is_empty preds then Some `Other else None
| Procdesc.Node.Join_node ->
(* Join node has the exception that it may be without predecessors
and pointing to between_join_and_exit which points to an exit node.
This happens when the if branches end with a return.
Nested if statements, where all branches have return statements,
introduce a sequence of join nodes *)
if
(List.is_empty preds && not (is_consecutive_join_nodes n Procdesc.NodeSet.empty))
|| (not (List.is_empty preds) && List.is_empty succs)
then Some `Join
else None
in
let rec find_first_broken nodes res_broken_node =
match nodes with
| [] ->
res_broken_node
| n :: nodes' ->
let broken_node = find_broken_node n in
match broken_node with
| None ->
find_first_broken nodes' res_broken_node
| Some `Join ->
find_first_broken nodes' broken_node
| Some `Other ->
broken_node
in
find_first_broken (Procdesc.get_nodes proc_desc) None
let load_statement = let load_statement =
ResultsDatabase.register_statement "SELECT cfgs FROM source_files WHERE source_file = :k" ResultsDatabase.register_statement "SELECT cfgs FROM source_files WHERE source_file = :k"

@ -32,9 +32,6 @@ val create_proc_desc : t -> ProcAttributes.t -> Procdesc.t
val iter_all_nodes : ?sorted:bool -> t -> f:(Procdesc.t -> Procdesc.Node.t -> unit) -> unit val iter_all_nodes : ?sorted:bool -> t -> f:(Procdesc.t -> Procdesc.Node.t -> unit) -> unit
(** Iterate over all the nodes in the cfg *) (** Iterate over all the nodes in the cfg *)
val proc_cfg_broken_for_node : Procdesc.t -> [`Join | `Other] option
(** checks whether a cfg for the given procdesc is connected or not *)
val save_attributes : SourceFile.t -> t -> unit val save_attributes : SourceFile.t -> t -> unit
(** Save the .attr files for the procedures in the cfg. *) (** Save the .attr files for the procedures in the cfg. *)

@ -815,3 +815,68 @@ let specialize_with_block_args callee_pdesc pname_with_block_args block_args =
"signature of specialized method %a@." pp_signature resolved_pdesc ; "signature of specialized method %a@." pp_signature resolved_pdesc ;
convert_cfg ~callee_pdesc ~resolved_pdesc convert_cfg ~callee_pdesc ~resolved_pdesc
~f_instr_list:(specialize_with_block_args_instrs resolved_pdesc substitutions) ~f_instr_list:(specialize_with_block_args_instrs resolved_pdesc substitutions)
let is_connected proc_desc =
let is_exit_node n = match Node.get_kind n with Node.Exit_node _ -> true | _ -> false in
let is_between_join_and_exit_node n =
match Node.get_kind n with
| Node.Stmt_node "between_join_and_exit" | Node.Stmt_node "Destruction" -> (
match Node.get_succs n with [n'] when is_exit_node n' -> true | _ -> false )
| _ ->
false
in
let rec is_consecutive_join_nodes n visited =
match Node.get_kind n with
| Node.Join_node
-> (
if NodeSet.mem n visited then false
else
let succs = Node.get_succs n in
match succs with
| [n'] ->
is_consecutive_join_nodes n' (NodeSet.add n visited)
| _ ->
false )
| _ ->
is_between_join_and_exit_node n
in
let find_broken_node n =
let succs = Node.get_succs n in
let preds = Node.get_preds n in
match Node.get_kind n with
| Node.Start_node _ ->
if List.is_empty succs || not (List.is_empty preds) then Error `Other else Ok ()
| Node.Exit_node _ ->
if not (List.is_empty succs) || List.is_empty preds then Error `Other else Ok ()
| Node.Stmt_node _ | Node.Prune_node _ | Node.Skip_node _ ->
if List.is_empty succs || List.is_empty preds then Error `Other else Ok ()
| Node.Join_node ->
(* Join node has the exception that it may be without predecessors
and pointing to between_join_and_exit which points to an exit node.
This happens when the if branches end with a return.
Nested if statements, where all branches have return statements,
introduce a sequence of join nodes *)
if
(List.is_empty preds && not (is_consecutive_join_nodes n NodeSet.empty))
|| (not (List.is_empty preds) && List.is_empty succs)
then Error `Join
else Ok ()
in
(* unconnected nodes generated by Join nodes are expected *)
let skip_join_errors current_status node =
match find_broken_node node with
| Ok () ->
Ok current_status
| Error `Join ->
Ok (Some `Join)
| Error _ as other_error ->
other_error
in
match List.fold_result (get_nodes proc_desc) ~init:None ~f:skip_join_errors with
| Ok (Some `Join) ->
Error `Join
| Ok None ->
Ok ()
| Error _ as error ->
error

@ -211,9 +211,8 @@ val pp_local : Format.formatter -> ProcAttributes.var_data -> unit
val is_specialized : t -> bool val is_specialized : t -> bool
(* true if pvar is a captred variable of a cpp lambda or obcj block *)
val is_captured_var : t -> Pvar.t -> bool val is_captured_var : t -> Pvar.t -> bool
(** true if pvar is a captured variable of a cpp lambda or obcj block *)
val has_modify_in_block_attr : t -> Pvar.t -> bool val has_modify_in_block_attr : t -> Pvar.t -> bool
@ -229,3 +228,6 @@ val specialize_with_block_args : t -> Typ.Procname.t -> Exp.closure option list
a) the block parameters are replaces with the closures a) the block parameters are replaces with the closures
b) the parameters of the method are extended with parameters for the captured variables b) the parameters of the method are extended with parameters for the captured variables
in the closures *) in the closures *)
val is_connected : t -> (unit, [`Join | `Other]) Result.t
(** checks whether a cfg for the given procdesc is connected or not *)

@ -81,10 +81,10 @@ module CFrontend_decl_funct (T : CModule_type.CTranslation) : CModule_type.CFron
Procdesc.Node.add_locals_ret_declaration start_node proc_attributes Procdesc.Node.add_locals_ret_declaration start_node proc_attributes
(Procdesc.get_locals procdesc) ; (Procdesc.get_locals procdesc) ;
Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ; Procdesc.node_set_succs_exn procdesc start_node meth_body_nodes [] ;
match Cfg.proc_cfg_broken_for_node procdesc with match Procdesc.is_connected procdesc with
| None -> | Ok () ->
() ()
| Some broken_node -> | Error broken_node ->
let lang = let lang =
CFrontend_config.string_of_clang_lang trans_unit_ctx.CFrontend_config.lang CFrontend_config.string_of_clang_lang trans_unit_ctx.CFrontend_config.lang
in in

Loading…
Cancel
Save