Builder that constructs a CFG from a given AST. This GraphBuilder facilitates constructing the DAG that forms the CFG when nodes are supplied in lexical order (i.e., top-down, depth first). Under these conditions, it supports building patterns found in typical structured programs. This
| 229 | |
| 230 | |
| 231 | class GraphBuilder(object): |
| 232 | """Builder that constructs a CFG from a given AST. |
| 233 | |
| 234 | This GraphBuilder facilitates constructing the DAG that forms the CFG when |
| 235 | nodes |
| 236 | are supplied in lexical order (i.e., top-down, depth first). Under these |
| 237 | conditions, it supports building patterns found in typical structured |
| 238 | programs. |
| 239 | |
| 240 | This builder ignores the flow generated by exceptions, which are assumed to |
| 241 | always be catastrophic and present purely for diagnostic purposes (e.g. to |
| 242 | print debug information). Statements like raise and try/catch sections are |
| 243 | allowed and will generate control flow edges, but ordinaty statements are |
| 244 | assumed not to raise exceptions. |
| 245 | |
| 246 | Finally sections are also correctly interleaved between break/continue/return |
| 247 | nodes and their subsequent statements. |
| 248 | |
| 249 | Important concepts: |
| 250 | * nodes - nodes refer refer to CFG nodes; AST nodes are qualified explicitly |
| 251 | * leaf set - since the graph is constructed gradually, a leaf set maintains |
| 252 | the CFG nodes that will precede the node that the builder expects to |
| 253 | receive next; when an ordinary node is added, it is connected to the |
| 254 | existing leaves and it in turn becomes the new leaf |
| 255 | * jump nodes - nodes that should generate edges other than what |
| 256 | ordinary nodes would; these correspond to break, continue and return |
| 257 | statements |
| 258 | * sections - logical delimiters for subgraphs that require special |
| 259 | edges; there are various types of nodes, each admitting various |
| 260 | types of jump nodes; sections are identified by their corresponding AST |
| 261 | node |
| 262 | """ |
| 263 | |
| 264 | # TODO(mdan): Perhaps detail this in a markdown doc. |
| 265 | # TODO(mdan): Add exception support. |
| 266 | |
| 267 | def __init__(self, parent_ast_node): |
| 268 | self.reset() |
| 269 | self.parent = parent_ast_node |
| 270 | |
| 271 | def reset(self): |
| 272 | """Resets the state of this factory.""" |
| 273 | self.head = None |
| 274 | self.errors = set() |
| 275 | self.node_index = {} |
| 276 | |
| 277 | # TODO(mdan): Too many primitives. Use classes. |
| 278 | self.leaves = set() |
| 279 | |
| 280 | # Note: This mechanism requires that nodes are added in lexical order (top |
| 281 | # to bottom, depth first). |
| 282 | self.active_stmts = set() |
| 283 | self.owners = {} # type: Set[any] |
| 284 | self.forward_edges = set() # type: Tuple[Node, Node] # (from, to) |
| 285 | |
| 286 | self.finally_sections = {} |
| 287 | # Dict values represent (entry, exits) |
| 288 | self.finally_section_subgraphs = { |
no outgoing calls
no test coverage detected