@@ -881,14 +881,29 @@ class PathNode extends TPathNode {
881881 /** Gets the summary of the path underlying this path node. */
882882 PathSummary getPathSummary ( ) { result = summary }
883883
884- /** Gets a successor node of this path node. */
885- PathNode getASuccessor ( ) {
884+ /**
885+ * Gets a successor node of this path node, including hidden nodes.
886+ */
887+ private PathNode getASuccessorInternal ( ) {
886888 exists ( DataFlow:: Node succ , PathSummary newSummary |
887889 flowStep ( nd , id ( cfg ) , succ , newSummary ) and
888890 result = MkPathNode ( succ , id ( cfg ) , summary .append ( newSummary ) )
889891 )
890892 }
891893
894+ /**
895+ * Gets a successor of this path node, if it is a hidden node.
896+ */
897+ private PathNode getAHiddenSuccessor ( ) {
898+ isHidden ( ) and
899+ result = getASuccessorInternal ( )
900+ }
901+
902+ /** Gets a successor node of this path node. */
903+ PathNode getASuccessor ( ) {
904+ result = getASuccessorInternal ( ) .getAHiddenSuccessor * ( )
905+ }
906+
892907 /** Gets a textual representation of this path node. */
893908 string toString ( ) { result = nd .toString ( ) }
894909
@@ -904,6 +919,19 @@ class PathNode extends TPathNode {
904919 ) {
905920 nd .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
906921 }
922+
923+ /**
924+ * Holds if this node is hidden from paths in path explanation queries, except
925+ * in cases where it is the source or sink.
926+ */
927+ predicate isHidden ( ) {
928+ // Skip phi, refinement, and capture nodes
929+ nd .( DataFlow:: SsaDefinitionNode ) .getSsaVariable ( ) .getDefinition ( ) instanceof SsaImplicitDefinition
930+ or
931+ // Skip to the top of big left-leaning string concatenation trees.
932+ nd = any ( AddExpr add ) .flow ( ) and
933+ nd = any ( AddExpr add ) .getAnOperand ( ) .flow ( )
934+ }
907935}
908936
909937/**
@@ -925,7 +953,11 @@ class SinkPathNode extends PathNode {
925953 */
926954module PathGraph {
927955 /** Holds if `nd` is a node in the graph of data flow path explanations. */
928- query predicate nodes ( PathNode nd ) { any ( ) }
956+ query predicate nodes ( PathNode nd ) {
957+ not nd .isHidden ( ) or
958+ nd instanceof SourcePathNode or
959+ nd instanceof SinkPathNode
960+ }
929961
930962 /** Holds if `pred` → `succ` is an edge in the graph of data flow path explanations. */
931963 query predicate edges ( PathNode pred , PathNode succ ) { pred .getASuccessor ( ) = succ }
0 commit comments