diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowImplSpecific.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowImplSpecific.qll index cd244e6ca35..dff14dc7426 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowImplSpecific.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowImplSpecific.qll @@ -21,4 +21,6 @@ module PowershellDataFlow implements InputSig { class ParameterNode = Private::ParameterNodeImpl; Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) } + + predicate neverSkipInPathGraph = Private::neverSkipInPathGraph/1; } diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll index c1292e34bae..e7764e6b607 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -31,6 +31,9 @@ abstract class NodeImpl extends Node { /** Do not call: use `toString()` instead. */ abstract string toStringImpl(); + + /** Holds if this node should be hidden from path explanations. */ + predicate nodeIsHidden() { none() } } private class ExprNodeImpl extends ExprNode, NodeImpl { @@ -284,7 +287,13 @@ private string approxKnownElementIndex(ConstantValue cv) { import Cached /** Holds if `n` should be hidden from path explanations. */ -predicate nodeIsHidden(Node n) { none() } +predicate nodeIsHidden(Node n) { n.(NodeImpl).nodeIsHidden() } + +/** + * Holds if `n` should never be skipped over in the `PathGraph` and in path + * explanations. + */ +predicate neverSkipInPathGraph(Node n) { isReturned(n.(AstNode).getCfgNode()) } /** An SSA node. */ abstract class SsaNode extends NodeImpl, TSsaNode { @@ -795,6 +804,8 @@ private class ImplicitWrapNode extends TImplicitWrapNode, NodeImpl { override Location getLocationImpl() { result = n.getLocation() } override string toStringImpl() { result = "implicit unwrapping of " + n.toString() } + + override predicate nodeIsHidden() { any() } } /** @@ -829,6 +840,8 @@ private class ReturnNodeImpl extends TReturnNodeImpl, NodeImpl { override Location getLocationImpl() { result = scope.getLocation() } override string toStringImpl() { result = "return value for " + scope.toString() } + + override predicate nodeIsHidden() { any() } } /** A node that performs a type cast. */ diff --git a/powershell/ql/test/library-tests/dataflow/returns/test.expected b/powershell/ql/test/library-tests/dataflow/returns/test.expected index e851cb13654..dbd31969033 100644 --- a/powershell/ql/test/library-tests/dataflow/returns/test.expected +++ b/powershell/ql/test/library-tests/dataflow/returns/test.expected @@ -1,48 +1,32 @@ models edges -| test.ps1:1:25:3:2 | return value for {...} | test.ps1:5:6:5:20 | callSourceOnce | provenance | | -| test.ps1:2:5:2:15 | Source | test.ps1:2:5:2:15 | implicit unwrapping of Source | provenance | | -| test.ps1:2:5:2:15 | implicit unwrapping of Source | test.ps1:1:25:3:2 | return value for {...} | provenance | | +| test.ps1:2:5:2:15 | Source | test.ps1:5:6:5:20 | callSourceOnce | provenance | | | test.ps1:5:6:5:20 | callSourceOnce | test.ps1:6:6:6:8 | x | provenance | | -| test.ps1:8:26:11:2 | return value for {...} | test.ps1:13:6:13:21 | callSourceTwice | provenance | | -| test.ps1:9:5:9:15 | Source | test.ps1:9:5:9:15 | implicit unwrapping of Source | provenance | | -| test.ps1:9:5:9:15 | implicit unwrapping of Source | test.ps1:8:26:11:2 | return value for {...} | provenance | | -| test.ps1:10:5:10:15 | Source | test.ps1:10:5:10:15 | implicit unwrapping of Source | provenance | | -| test.ps1:10:5:10:15 | implicit unwrapping of Source | test.ps1:8:26:11:2 | return value for {...} | provenance | | +| test.ps1:9:5:9:15 | Source | test.ps1:13:6:13:21 | callSourceTwice | provenance | | +| test.ps1:10:5:10:15 | Source | test.ps1:13:6:13:21 | callSourceTwice | provenance | | | test.ps1:13:6:13:21 | callSourceTwice | test.ps1:14:6:14:8 | x | provenance | | -| test.ps1:16:24:18:2 | return value for {...} | test.ps1:20:6:20:19 | returnSource1 | provenance | | -| test.ps1:17:12:17:22 | Source | test.ps1:17:12:17:22 | implicit unwrapping of Source | provenance | | -| test.ps1:17:12:17:22 | implicit unwrapping of Source | test.ps1:16:24:18:2 | return value for {...} | provenance | | +| test.ps1:17:12:17:22 | Source | test.ps1:20:6:20:19 | returnSource1 | provenance | | | test.ps1:20:6:20:19 | returnSource1 | test.ps1:21:6:21:8 | x | provenance | | -| test.ps1:23:24:28:2 | return value for {...} | test.ps1:30:6:30:19 | returnSource2 | provenance | | -| test.ps1:24:10:24:20 | Source | test.ps1:25:5:25:7 | implicit unwrapping of x | provenance | | -| test.ps1:25:5:25:7 | implicit unwrapping of x | test.ps1:23:24:28:2 | return value for {...} | provenance | | -| test.ps1:26:10:26:20 | Source | test.ps1:27:12:27:14 | implicit unwrapping of y | provenance | | -| test.ps1:27:12:27:14 | implicit unwrapping of y | test.ps1:23:24:28:2 | return value for {...} | provenance | | +| test.ps1:24:10:24:20 | Source | test.ps1:25:5:25:7 | x | provenance | | +| test.ps1:25:5:25:7 | x | test.ps1:30:6:30:19 | returnSource2 | provenance | | +| test.ps1:26:10:26:20 | Source | test.ps1:27:12:27:14 | y | provenance | | +| test.ps1:27:12:27:14 | y | test.ps1:30:6:30:19 | returnSource2 | provenance | | | test.ps1:30:6:30:19 | returnSource2 | test.ps1:31:6:31:8 | x | provenance | | nodes -| test.ps1:1:25:3:2 | return value for {...} | semmle.label | return value for {...} | | test.ps1:2:5:2:15 | Source | semmle.label | Source | -| test.ps1:2:5:2:15 | implicit unwrapping of Source | semmle.label | implicit unwrapping of Source | | test.ps1:5:6:5:20 | callSourceOnce | semmle.label | callSourceOnce | | test.ps1:6:6:6:8 | x | semmle.label | x | -| test.ps1:8:26:11:2 | return value for {...} | semmle.label | return value for {...} | | test.ps1:9:5:9:15 | Source | semmle.label | Source | -| test.ps1:9:5:9:15 | implicit unwrapping of Source | semmle.label | implicit unwrapping of Source | | test.ps1:10:5:10:15 | Source | semmle.label | Source | -| test.ps1:10:5:10:15 | implicit unwrapping of Source | semmle.label | implicit unwrapping of Source | | test.ps1:13:6:13:21 | callSourceTwice | semmle.label | callSourceTwice | | test.ps1:14:6:14:8 | x | semmle.label | x | -| test.ps1:16:24:18:2 | return value for {...} | semmle.label | return value for {...} | | test.ps1:17:12:17:22 | Source | semmle.label | Source | -| test.ps1:17:12:17:22 | implicit unwrapping of Source | semmle.label | implicit unwrapping of Source | | test.ps1:20:6:20:19 | returnSource1 | semmle.label | returnSource1 | | test.ps1:21:6:21:8 | x | semmle.label | x | -| test.ps1:23:24:28:2 | return value for {...} | semmle.label | return value for {...} | | test.ps1:24:10:24:20 | Source | semmle.label | Source | -| test.ps1:25:5:25:7 | implicit unwrapping of x | semmle.label | implicit unwrapping of x | +| test.ps1:25:5:25:7 | x | semmle.label | x | | test.ps1:26:10:26:20 | Source | semmle.label | Source | -| test.ps1:27:12:27:14 | implicit unwrapping of y | semmle.label | implicit unwrapping of y | +| test.ps1:27:12:27:14 | y | semmle.label | y | | test.ps1:30:6:30:19 | returnSource2 | semmle.label | returnSource2 | | test.ps1:31:6:31:8 | x | semmle.label | x | subpaths