1010 * The calculation is in two stages. First, a graph of _sub-nodes_ is produced.
1111 * A sub-node is either an actual CFG node or a _virtual node_. Second, the
1212 * virtual nodes are eliminated from the graph by collapsing edges such that
13- * any _actual nodes_ connected through zero or more _virtual nodes_ are still
14- * connected in the final graph.
13+ * any _actual sub- nodes_ connected through zero or more _virtual sub- nodes_
14+ * are still connected in the final graph.
1515 *
1616 * The graph of sub-nodes is produced by a comprehensive case analysis that
1717 * specifies the shape of the CFG for all known language constructs. The case
1818 * analysis is large but does _not_ contain recursion. Recursion is needed in
1919 * the second stage in order to collapse virtual nodes, but that recursion is
20- * simply a transitive closure and can be fast.
20+ * simply a transitive closure and so is fast.
2121 *
2222 * A sub-node is a pair `(Node, Pos)`, where the type `Node` is
23- * `ControlFlowNode`. `Pos` is either an "at"-position, which means it's the
24- * control-flow node itself, or a different value, which means the sub-node is
25- * virtual. The most important virtual positions are "before" and "after". They
26- * represent the points in control flow just before and after evaluating the
27- * associated node and its children.
23+ * `ControlFlowNode`, and `Pos` is usually one of three values: "at", "before",
24+ * or "after". The "at" position represents the control-flow node itself, and
25+ * sub-nodes with "at"-positions are what we call _actual_ sub-nodes. Other
26+ * positions are _virtual_, and they are used for forming paths between actual
27+ * sub-nodes and will get erased to produce the final graph. The "before" and
28+ * "after" positions represent the points in control flow just before and after
29+ * evaluating the associated node and its children.
2830 *
2931 * The computation of the sub-edges is a large disjunction in which each case
3032 * contributes all the edges for a particular type of node. As an example,
4143 * after(e2) -> at(e)
4244 * at(e) -> after(e)
4345 *
44- * These three edges are not connected, but they will be part of a connected
46+ * These four edges are not all connected, but they will be part of a connected
4547 * graph when all expressions under `e1` and `e2` are added as well. Suppose
4648 * `e1` and `e2` are of type Literal. Then they contribute the following edges.
4749 *
6062 * To produce all edges around each control-flow node without recursion, we
6163 * need to pre-compute the targets of exception sources (throw, propagating
6264 * handlers, ...) and short-circuiting operators (||, ? :, ...). This
63- * pre-computation involves recursion, but it's quick to compute because in
65+ * pre-computation involves recursion, but it's quick to compute because it
6466 * only involves the nodes themselves and their (transitive) parents.
6567 *
66- * For many AST nodes, their control flow can be described in simpler terms
67- * than the full generality of describing each of their individual sub-edges .
68- * To add control flow for a new AST construct, one of the following predicates
69- * can be used, listed roughly in order of increasing generality .
68+ * Many kinds of AST nodes share the same pattern of control flow. To add
69+ * control flow for a new AST construct, use one of the following predicates .
70+ * They are listed in order of increasing generality, where less general
71+ * predicates can be extended with less effort .
7072 *
7173 * - PostOrderNode and PreOrderNode
7274 * - straightLineSparse
8082private import cpp
8183private import semmle.code.cpp.controlflow.internal.SyntheticDestructorCalls
8284
83- /** A control-flow node. */
85+ /**
86+ * A control-flow node. This class exists to provide a shorter name than
87+ * `ControlFlowNodeBase` within this file and to avoid a seemingly cyclic
88+ * dependency on the `ControlFlowNode` class, whose implementation relies on
89+ * this file.
90+ */
8491private class Node extends ControlFlowNodeBase {
8592 /**
8693 * Gets the nearest control-flow node that's a parent of this one, never
@@ -91,11 +98,15 @@ private class Node extends ControlFlowNodeBase {
9198 or
9299 result = this .( Stmt ) .getParent ( )
93100 or
94- // An Initializer under a ConditionDeclExpr is not part of the CFG.
95101 result .( DeclStmt ) .getADeclaration ( ) .( LocalVariable ) = this .( Initializer ) .getDeclaration ( )
96102 // It's possible that the VLA cases of DeclStmt (see
97103 // getControlOrderChildSparse) should also be here, but that currently
98104 // won't make a difference in practice.
105+ //
106+ // An `Initializer` under a `ConditionDeclExpr` is not part of the CFG;
107+ // only the `getExpr()` of the `Initializer` is in the CFG. That can be
108+ // changed when we no longer need compatibility with the extractor-based
109+ // CFG.
99110 }
100111}
101112
0 commit comments