@@ -74,9 +74,9 @@ signature module AstSig<LocationSig Location> {
7474 Expr getExpr ( ) ;
7575 }
7676
77- /** An if statement. */
77+ /** An `if` statement. */
7878 class IfStmt extends Stmt {
79- /** Gets the condition of this if statement. */
79+ /** Gets the condition of this `if` statement. */
8080 Expr getCondition ( ) ;
8181
8282 /** Gets the `then` (true) branch of this `if` statement. */
@@ -231,6 +231,8 @@ signature module AstSig<LocationSig Location> {
231231 * This is most often the same as the AST order, but can be different in some
232232 * languages if the language allows a default case to appear before other
233233 * cases.
234+ *
235+ * The values do not need to be contiguous; only the relative ordering matters.
234236 */
235237 default int getCaseControlFlowOrder ( Switch s , Case c ) { s .getCase ( result ) = c }
236238
@@ -308,7 +310,7 @@ signature module AstSig<LocationSig Location> {
308310 * completed by subsequent instatiation of `Make1` and `Make2`.
309311 *
310312 * A complete instantiation can look as follows:
311- * ```
313+ * ```ql
312314 * private module Input implements InputSig1, InputSig2 { .. }
313315 * private module Cfg0 = Make0<Location, Ast>;
314316 * private module Cfg1 = Make1<Input>;
@@ -347,34 +349,49 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
347349 /**
348350 * Holds if the value of `child` is propagated to `parent`. For example,
349351 * the right-hand side of short-circuiting expressions.
352+ *
353+ * This predicate is only relevant for AST constructs that are not already
354+ * handled by this library.
350355 */
351356 default predicate propagatesValue ( AstNode child , AstNode parent ) { none ( ) }
352357
353358 /**
354359 * Holds if `n` is in a conditional context of kind `kind`. For example,
355360 * the left-hand side of a short-circuiting `&&` expression is in a
356361 * boolean conditional context.
362+ *
363+ * This predicate is only relevant for AST constructs that are not already
364+ * handled by this library.
357365 */
358366 default predicate inConditionalContext ( AstNode n , ConditionKind kind ) { none ( ) }
359367
360368 /**
361369 * Holds if `e` is executed in pre-order. This is typical for expressions
362370 * that are pure control-flow constructions without calculation or side
363371 * effects, such as `ConditionalExpr` and `Switch` expressions.
372+ *
373+ * This predicate is only relevant for AST constructs that are not already
374+ * handled by this library.
364375 */
365376 default predicate preOrderExpr ( Expr e ) { none ( ) }
366377
367378 /**
368379 * Holds if `n` is executed in post-order or in-order. This means that an
369380 * additional node is created to represent `n` in the control flow graph.
370381 * Otherwise, `n` is represented by the "before" node.
382+ *
383+ * This predicate is only relevant for AST constructs that are not already
384+ * handled by this library.
371385 */
372386 default predicate postOrInOrder ( AstNode n ) { none ( ) }
373387
374388 /**
375389 * Holds if an additional node tagged with `tag` should be created for
376390 * `n`. Edges targeting such nodes are labeled with `t` and therefore `t`
377391 * should be unique for a given `(n,tag)` pair.
392+ *
393+ * This predicate is only relevant for AST constructs that are not already
394+ * handled by this library.
378395 */
379396 default predicate additionalNode ( AstNode n , string tag , NormalSuccessor t ) { none ( ) }
380397
@@ -446,9 +463,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
446463 not postOrInOrder ( parent ) and
447464 parent .( BinaryExpr ) .getRightOperand ( ) = child
448465 or
449- parent .( ConditionalExpr ) .getThen ( ) = child
450- or
451- parent .( ConditionalExpr ) .getElse ( ) = child
466+ parent = any ( ConditionalExpr ce | child = [ ce .getThen ( ) , ce .getElse ( ) ] )
452467 or
453468 parent .( BlockStmt ) .getLastStmt ( ) = child
454469 or
@@ -581,15 +596,19 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
581596 cached
582597 private newtype TNode =
583598 TBeforeNode ( AstNode n ) { Input1:: cfgCachedStageRef ( ) and exists ( getEnclosingCallable ( n ) ) } or
584- TAstNode ( AstNode n ) { postOrInOrder ( n ) } or
585- TAfterValueNode ( AstNode n , ConditionalSuccessor t ) { inConditionalContext ( n , t .getKind ( ) ) } or
599+ TAstNode ( AstNode n ) { postOrInOrder ( n ) and exists ( getEnclosingCallable ( n ) ) } or
600+ TAfterValueNode ( AstNode n , ConditionalSuccessor t ) {
601+ inConditionalContext ( n , t .getKind ( ) ) and exists ( getEnclosingCallable ( n ) )
602+ } or
586603 TAfterNode ( AstNode n ) {
587604 exists ( getEnclosingCallable ( n ) ) and
588605 not inConditionalContext ( n , _) and
589606 not cannotTerminateNormally ( n ) and
590607 not simpleLeafNode ( n )
591608 } or
592- TAdditionalNode ( AstNode n , string tag ) { additionalNode ( n , tag , _) } or
609+ TAdditionalNode ( AstNode n , string tag ) {
610+ additionalNode ( n , tag , _) and exists ( getEnclosingCallable ( n ) )
611+ } or
593612 TEntryNode ( Callable c ) { exists ( callableGetBody ( c ) ) } or
594613 TAnnotatedExitNode ( Callable c , Boolean normal ) { exists ( callableGetBody ( c ) ) } or
595614 TExitNode ( Callable c ) { exists ( callableGetBody ( c ) ) }
@@ -636,6 +655,15 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
636655 this = TAfterValueNode ( n , t )
637656 or
638657 exists ( ConditionalSuccessor t0 | this = TAfterValueNode ( n , t0 ) |
658+ // When this predicate is used to identify the end point of a step,
659+ // the kinds of `t` and `t0` may not match. For example, in
660+ // `(x || y) ?? z`, the `||` may short-circuit with a known boolean
661+ // value `t`, but it occurs in a nullness conditional context, which
662+ // means that the `t0` has nullness kind. In these cases we check
663+ // whether there is an implication that allows translatiion from `t`
664+ // to `t0`, and if not `t0` is simply unrestricted. If the kinds did
665+ // match, then no translation is needed and we're covered by the
666+ // `this = TAfterValueNode(n, t)` case above.
639667 Input1:: successorValueImplies ( t , t0 )
640668 or
641669 not Input1:: successorValueImplies ( t , _) and
@@ -738,7 +766,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
738766 override string getIdTag ( ) { result = "before" }
739767
740768 override string toString ( ) {
741- if postOrInOrder ( n ) then result = "Before " + n . toString ( ) else result = n .toString ( )
769+ if postOrInOrder ( n ) then result = "Before " + n else result = n .toString ( )
742770 }
743771 }
744772
@@ -768,7 +796,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
768796 t .getValue ( ) = false and result = "after-false"
769797 }
770798
771- override string toString ( ) { result = "After " + n . toString ( ) + " [" + t . toString ( ) + "]" }
799+ override string toString ( ) { result = "After " + n + " [" + t + "]" }
772800 }
773801
774802 private class AfterNode extends NodeImpl , TAfterNode {
@@ -780,7 +808,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
780808
781809 override string getIdTag ( ) { result = "after" }
782810
783- override string toString ( ) { result = "After " + n . toString ( ) }
811+ override string toString ( ) { result = "After " + n }
784812 }
785813
786814 private class AdditionalNode extends NodeImpl , TAdditionalNode {
@@ -795,7 +823,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
795823
796824 override string getIdTag ( ) { result = "add. " + tag }
797825
798- override string toString ( ) { result = tag + " " + n . toString ( ) }
826+ override string toString ( ) { result = tag + " " + n }
799827 }
800828
801829 final private class EntryNodeImpl extends NodeImpl , TEntryNode {
@@ -877,7 +905,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
877905 or
878906 exists ( AbruptSuccessor t , Input1:: Label l |
879907 this = TLabeledAbruptCompletion ( t , l ) and
880- result = t . toString ( ) + " " + l . toString ( )
908+ result = t + " " + l
881909 )
882910 }
883911
@@ -913,6 +941,9 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
913941 * Holds if `ast` may result in an abrupt completion `c` originating at
914942 * `n`. The boolean `always` indicates whether the abrupt completion
915943 * always occurs or whether `n` may also terminate normally.
944+ *
945+ * This predicate is only relevant for AST constructs that are not already
946+ * handled by this library.
916947 */
917948 predicate beginAbruptCompletion (
918949 AstNode ast , PreControlFlowNode n , AbruptCompletion c , boolean always
@@ -921,10 +952,18 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
921952 /**
922953 * Holds if an abrupt completion `c` from within `ast` is caught with
923954 * flow continuing at `n`.
955+ *
956+ * This predicate is only relevant for AST constructs that are not already
957+ * handled by this library.
924958 */
925959 predicate endAbruptCompletion ( AstNode ast , PreControlFlowNode n , AbruptCompletion c ) ;
926960
927- /** Holds if there is a local non-abrupt step from `n1` to `n2`. */
961+ /**
962+ * Holds if there is a local non-abrupt step from `n1` to `n2`.
963+ *
964+ * This predicate is only relevant for AST constructs that are not already
965+ * handled by this library.
966+ */
928967 predicate step ( PreControlFlowNode n1 , PreControlFlowNode n2 ) ;
929968 }
930969
@@ -1596,10 +1635,10 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
15961635 /** Gets an immediate successor of a given type, if any. */
15971636 ControlFlowNode getASuccessor ( SuccessorType t ) { succ ( this , result , t ) }
15981637
1599- /** Gets an immediate successor of this node. */
1638+ /** Gets an immediate successor of this node, if this is not an `ExitNode` . */
16001639 ControlFlowNode getASuccessor ( ) { result = this .getASuccessor ( _) }
16011640
1602- /** Gets an immediate predecessor of this node. */
1641+ /** Gets an immediate predecessor of this node, if this is not an `EntryNode` . */
16031642 ControlFlowNode getAPredecessor ( ) { result .getASuccessor ( ) = this }
16041643
16051644 /**
@@ -1656,11 +1695,11 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
16561695 }
16571696 }
16581697
1659- import CfgAlias
1698+ module Cfg = BB :: Make < Location , BbInput > ;
16601699
16611700 private module CfgAlias = Cfg;
16621701
1663- module Cfg = BB :: Make < Location , BbInput > ;
1702+ import CfgAlias
16641703 }
16651704
16661705 private module Additional {
@@ -1684,32 +1723,32 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
16841723
16851724 import Pp:: PrintGraph< Location , PrintGraphInput >
16861725
1687- /*
1688- * Consistency checks
1689- *
1690- * - there should be no dead ends except at ExitNodes
1691- * - inConditionalContext(n, kind) kind must be unique for n
1692- * - flow must preserve getEnclosingCallable
1693- * - additionalNode(AstNode n, string tag, NormalSuccessor t) should have a unique t for (n, tag)
1694- * - if "before" is reachable and node is post-or-in-order, then "in" must generally be reachable
1695- */
1696-
16971726 /** Provides a set of consistency queries. */
16981727 module Consistency {
1699- /** Holds if `node` is lacking a successor. */
1728+ /**
1729+ * Holds if `node` is lacking a successor.
1730+ *
1731+ * There should be no dead ends except at `ExitNode`s.
1732+ */
17001733 query predicate deadEnd ( ControlFlowNode node ) {
17011734 not node instanceof ControlFlow:: ExitNode and
17021735 not exists ( node .getASuccessor ( _) )
17031736 }
17041737
1705- /** Holds if `n` is in a conditional context with multiple condition kinds. */
1738+ /**
1739+ * Holds if `n` is in a conditional context with multiple condition kinds.
1740+ *
1741+ * For `inConditionalContext(n, kind)`, the `kind` must be unique for a given `n`.
1742+ */
17061743 query predicate nonUniqueInConditionalContext ( AstNode n ) {
17071744 1 < strictcount ( ConditionKind kind | inConditionalContext ( n , kind ) )
17081745 }
17091746
17101747 /**
17111748 * Holds if `n1` steps to `n2` with successor type `t` but they belong
17121749 * to different callables.
1750+ *
1751+ * Flow must preserve `getEnclosingCallable`.
17131752 */
17141753 query predicate nonLocalStep ( ControlFlowNode n1 , SuccessorType t , ControlFlowNode n2 ) {
17151754 n1 .getASuccessor ( t ) = n2 and
@@ -1719,12 +1758,21 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
17191758 /**
17201759 * Holds if the additional node for a given AST node and tag has
17211760 * multiple successor types.
1761+ *
1762+ * For `additionalNode(AstNode n, string tag, NormalSuccessor t)`,
1763+ * the `t` must be unique for a given `(n, tag)`.
17221764 */
17231765 query predicate ambiguousAdditionalNode ( AstNode n , string tag ) {
17241766 1 < strictcount ( NormalSuccessor t | additionalNode ( n , tag , t ) )
17251767 }
17261768
1727- /** Holds if the "in" node is unreachable for a post-or-in-order AST node. */
1769+ /**
1770+ * Holds if the "in" node is unreachable for a post-or-in-order AST node.
1771+ *
1772+ * If the "before" node of a post-or-in-order AST node is reachable,
1773+ * then the "in" node should generally be reachable as well. If not,
1774+ * it may indicate missing control flow edges.
1775+ */
17281776 query predicate missingInNodeForPostOrInOrder ( AstNode ast ) {
17291777 postOrInOrder ( ast ) and
17301778 exists ( ControlFlowNode before | before .isBefore ( ast ) ) and
@@ -1748,7 +1796,13 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
17481796 )
17491797 }
17501798
1751- /** Holds if `node` has multiple successors of the same type `t`. */
1799+ /**
1800+ * Holds if `node` has multiple successors of the same type `t`.
1801+ *
1802+ * In most cases, multiple successors are distinguished by their
1803+ * successor types, for example the true and false successors of a
1804+ * condition.
1805+ */
17521806 query predicate multipleSuccessors (
17531807 ControlFlowNode node , SuccessorType t , ControlFlowNode successor
17541808 ) {
@@ -1774,7 +1828,13 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
17741828 not ( t instanceof DirectSuccessor and node instanceof ControlFlow:: EntryNode )
17751829 }
17761830
1777- /** Holds if `node` has conditional successors of different kinds. */
1831+ /**
1832+ * Holds if `node` has conditional successors of different kinds.
1833+ *
1834+ * The kind of a conditional successor is determined by the context
1835+ * of the node. For example, a condition in an `if` statement has
1836+ * boolean successors.
1837+ */
17781838 query predicate multipleConditionalSuccessorKinds (
17791839 ControlFlowNode node , ConditionalSuccessor t1 , ConditionalSuccessor t2 ,
17801840 ControlFlowNode succ1 , ControlFlowNode succ2
@@ -1784,7 +1844,13 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
17841844 succ2 = node .getASuccessor ( t2 )
17851845 }
17861846
1787- /** Holds if `node` has both a direct and a conditional successor type. */
1847+ /**
1848+ * Holds if `node` has both a direct and a conditional successor type.
1849+ *
1850+ * If a node is in a conditional context, it should only have
1851+ * conditional successors of the appropriate kind, and not other
1852+ * normal successors.
1853+ */
17881854 query predicate directAndConditionalSuccessors (
17891855 ControlFlowNode node , ConditionalSuccessor t1 , DirectSuccessor t2 ,
17901856 ControlFlowNode succ1 , ControlFlowNode succ2
@@ -1793,7 +1859,11 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
17931859 succ2 = node .getASuccessor ( t2 )
17941860 }
17951861
1796- /** Holds if `node` has a self-loop with successor type `t`. */
1862+ /**
1863+ * Holds if `node` has a self-loop with successor type `t`.
1864+ *
1865+ * Self-loops are not expected in control flow graphs.
1866+ */
17971867 query predicate selfLoop ( ControlFlowNode node , SuccessorType t ) {
17981868 node .getASuccessor ( t ) = node
17991869 }
0 commit comments