@@ -1042,27 +1042,42 @@ class PathNode extends TPathNode {
10421042 }
10431043}
10441044
1045- private PathNode getASuccessor ( PathNode pnd ) {
1045+ /** Gets the mid node corresponding to `src`. */
1046+ private MidPathNode initialMidNode ( SourcePathNode src ) {
10461047 exists ( DataFlow:: Node nd , Configuration cfg , PathSummary summary |
1047- // source node to mid node
1048- pnd = MkSourceNode ( nd , cfg ) and
1049- isSourceNode ( nd , cfg , summary ) and
1050- result = MkMidNode ( nd , cfg , summary )
1051- or
1052- // mid node to mid node
1053- pnd = MkMidNode ( nd , cfg , summary ) and
1054- exists ( DataFlow:: Node succ , PathSummary newSummary |
1055- flowStep ( nd , id ( cfg ) , succ , newSummary ) and
1056- result = MkMidNode ( succ , id ( cfg ) , summary .append ( newSummary ) )
1057- )
1058- or
1059- // mid node to sink node
1060- pnd = MkMidNode ( nd , cfg , summary ) and
1061- isSinkNode ( nd , cfg , summary ) and
1062- result = MkSinkNode ( nd , cfg )
1048+ result .wraps ( nd , cfg , summary ) and
1049+ src = MkSourceNode ( nd , cfg ) and
1050+ isSourceNode ( nd , cfg , summary )
10631051 )
10641052}
10651053
1054+ /** Gets the mid node corresponding to `snk`. */
1055+ private MidPathNode finalMidNode ( SinkPathNode snk ) {
1056+ exists ( DataFlow:: Node nd , Configuration cfg , PathSummary summary |
1057+ result .wraps ( nd , cfg , summary ) and
1058+ snk = MkSinkNode ( nd , cfg ) and
1059+ isSinkNode ( nd , cfg , summary )
1060+ )
1061+ }
1062+
1063+ /**
1064+ * Gets a node to which data from `nd` may flow in one step.
1065+ */
1066+ private PathNode getASuccessor ( PathNode nd ) {
1067+ // source node to mid node
1068+ result = initialMidNode ( nd )
1069+ or
1070+ // mid node to mid node
1071+ exists ( Configuration cfg , DataFlow:: Node predNd , PathSummary summary , DataFlow:: Node succNd , PathSummary newSummary |
1072+ nd = MkMidNode ( predNd , cfg , summary ) and
1073+ flowStep ( predNd , id ( cfg ) , succNd , newSummary ) and
1074+ result = MkMidNode ( succNd , id ( cfg ) , summary .append ( newSummary ) )
1075+ )
1076+ or
1077+ // mid node to sink node
1078+ nd = finalMidNode ( result )
1079+ }
1080+
10661081private PathNode getASuccessorIfHidden ( PathNode nd ) {
10671082 nd .( MidPathNode ) .isHidden ( ) and
10681083 result = getASuccessor ( nd )
@@ -1083,6 +1098,11 @@ class MidPathNode extends PathNode, MkMidNode {
10831098 /** Gets the summary of the path underlying this path node. */
10841099 PathSummary getPathSummary ( ) { result = summary }
10851100
1101+ /** Holds if this path node wraps data-flow node `nd`, configuration `c` and summary `s`. */
1102+ predicate wraps ( DataFlow:: Node n , DataFlow:: Configuration c , PathSummary s ) {
1103+ nd = n and cfg = c and summary = s
1104+ }
1105+
10861106 /**
10871107 * Holds if this node is hidden from paths in path explanation queries, except
10881108 * in cases where it is the source or sink.
@@ -1095,12 +1115,6 @@ class MidPathNode extends PathNode, MkMidNode {
10951115 // Skip to the top of big left-leaning string concatenation trees.
10961116 nd = any ( AddExpr add ) .flow ( ) and
10971117 nd = any ( AddExpr add ) .getAnOperand ( ) .flow ( )
1098- or
1099- // Skip mid node immediately following a source node
1100- exists ( MkSourceNode ( nd , cfg ) )
1101- or
1102- // Skip mid node immediately preceding a sink node
1103- exists ( MkSinkNode ( nd , cfg ) )
11041118 }
11051119}
11061120
@@ -1127,9 +1141,48 @@ module PathGraph {
11271141 not nd .( MidPathNode ) .isHidden ( )
11281142 }
11291143
1144+ /**
1145+ * Gets a node to which data from `nd` may flow in one step, skipping over hidden nodes.
1146+ */
1147+ private PathNode succ0 ( PathNode nd ) {
1148+ result = getASuccessorIfHidden * ( nd .getASuccessor ( ) ) and
1149+ // skip hidden nodes
1150+ nodes ( nd ) and nodes ( result )
1151+ }
1152+
1153+ /**
1154+ * Gets a node to which data from `nd` may flow in one step, where outgoing edges from intermediate
1155+ * nodes are merged with any incoming edge from a corresponding source node.
1156+ *
1157+ * For example, assume that `src` is a source node for `nd1`, which has `nd2` as its direct
1158+ * successor. Then `succ0` will yield two edges `src` → `nd1` and `nd1` → `nd2`,
1159+ * to which `succ1` will add the edge `src` → `nd2`.
1160+ */
1161+ private PathNode succ1 ( PathNode nd ) {
1162+ result = succ0 ( nd )
1163+ or
1164+ result = succ0 ( initialMidNode ( nd ) )
1165+ }
1166+
1167+ /**
1168+ * Gets a node to which data from `nd` may flow in one step, where incoming edges into intermediate
1169+ * nodes are merged with any outgoing edge to a corresponding sink node.
1170+ *
1171+ * For example, assume that `snk` is a source node for `nd2`, which has `nd1` as its direct
1172+ * predecessor. Then `succ1` will yield two edges `nd1` → `nd2` and `nd2` → `snk`,
1173+ * while `succ2` will yield just one edge `nd1` → `snk`.
1174+ */
1175+ private PathNode succ2 ( PathNode nd ) {
1176+ result = succ1 ( nd )
1177+ or
1178+ succ1 ( nd ) = finalMidNode ( result )
1179+ }
1180+
11301181 /** Holds if `pred` → `succ` is an edge in the graph of data flow path explanations. */
11311182 query predicate edges ( PathNode pred , PathNode succ ) {
1132- succ = getASuccessorIfHidden * ( pred .getASuccessor ( ) ) and
1133- nodes ( pred ) and nodes ( succ )
1183+ succ = succ2 ( pred ) and
1184+ // skip over uninteresting edges
1185+ not succ = initialMidNode ( pred ) and
1186+ not pred = finalMidNode ( succ )
11341187 }
11351188}
0 commit comments