123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183(* Yoann Padioleau
*
* Copyright (C) 2009, 2010, 2011 Facebook
* Copyright (C) 2019 r2c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
* license.txt for more details.
*)openAst_generic(*****************************************************************************)(* Prelude *)(*****************************************************************************)(* A Control Flow Graph (CFG) for AST generic.
*
* Note that this is just for intra-procedural analysis. The CFG covers
* just one function. For inter-procedural analysis you may want to look
* at pfff/graph_code/ (or invest in learning datalog).
*
* history:
* - CFG for C for coccinelle
* - CFG for PHP for checkModule at facebook
* - CFG for AST generic for scheck at r2c
*)(*****************************************************************************)(* Types *)(*****************************************************************************)typenode={(* later: For now we just have node_kind, but with some data-flow
* analysis or with temporal logic we may want to add extra information
* in each CFG nodes.
* alt: We could also record such extra information in an external table
* that maps Ograph_extended.nodei, that is nodeid, to some information.
*)n:node_kind;(* for error report *)i:Parse_info.toption;}andnode_kind=(* special fake cfg nodes *)|Enter|Exit(* alt: An alternative is to store such information in the edges, but
* experience shows it's easier to encode it via regular nodes
*)|TrueNode|FalseNode|IfHeaderofexpr|WhileHeaderofexpr|DoHeader|DoWhileTailofexpr|ForHeader|ForeachHeader(* TODO of foreach_variable list *)|SwitchHeaderofexpr|SwitchEnd|Case|Default|Returnofexpr|Breakofexproption|Continueofexproption|TryHeader|CatchStart|Catch|TryEnd|Throwofexpr|Join|Parameterofparameter(* statements without multiple outgoing or ingoing edges, such
* as echo, expression statements, etc.
*)|SimpleStmtofsimple_stmt(* not used for now, was used in coccinelle:
| BlockStart of tok (* { *)
| BlockEnd of tok (* } *)
| Else
| Elsif
*)andsimple_stmt=|ExprStmtofexpr|TodoSimpleStmt(* TODO? expr includes Exit, Eval, Include, etc which
* also have an influence on the control flow ...
* We may want to uplift those constructors here and have
* a better expr type
*)(* For now there is just one kind of edge. Later we may have more,
* see the ShadowNode idea of Julia Lawall.
*)typeedge=Directtypeflow=(node,edge)Ograph_extended.ograph_mutabletypenodei=Ograph_extended.nodei(*****************************************************************************)(* String of *)(*****************************************************************************)letshort_string_of_node_kindnkind=matchnkindwith|Enter->"<enter>"|Exit->"<exit>"|SimpleStmt_->"<simplestmt>"|Parameter_->"<parameter>"|WhileHeader_->"while(...)"|TrueNode->"TRUE path"|FalseNode->"FALSE path"|IfHeader_->"if(...)"|Join->"<join>"|Return_->"return ...;"|DoHeader->"do"|DoWhileTail_->"while(...);"|Continue_->"continue ...;"|Break_->"break ...;"|ForHeader->"for(...)"|ForeachHeader->"foreach(...)"|SwitchHeader_->"switch(...)"|SwitchEnd->"<endswitch>"|Case->"case: ..."|Default->"default:"|TryHeader->"try"|CatchStart->"<catchstart>"|Catch->"catch(...)"|TryEnd->"<endtry>"|Throw_->"throw ...;"letshort_string_of_nodenode=short_string_of_node_kindnode.n(*****************************************************************************)(* Accessors *)(*****************************************************************************)letfind_nodefcfg=cfg#nodes#tolist|>Common.find_some(fun(nodei,node)->iffnodethenSomenodeielseNone)letfind_exitcfg=find_node(funnode->node.n=Exit)cfgletfind_entercfg=find_node(funnode->node.n=Enter)cfg(* using internally graphviz dot and ghostview on X11 *)let(display_flow:flow->unit)=funflow->flow|>Ograph_extended.print_ograph_mutable_generic~s_of_node:(fun(_nodei,node)->short_string_of_node_kindnode.n,None,None)