@@ -48,7 +48,7 @@ module LocalFlow {
4848
4949 /**
5050 * Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
51- * SSA definition `def.
51+ * SSA definition `def` .
5252 */
5353 predicate localSsaFlowStep ( Ssa:: Definition def , Node nodeFrom , Node nodeTo ) {
5454 // Flow from parameter into SSA definition
@@ -114,6 +114,12 @@ private module Cached {
114114 newtype TNode =
115115 TExprNode ( CfgNodes:: ExprCfgNode n ) or
116116 TReturningNode ( CfgNodes:: ReturningCfgNode n ) or
117+ TSynthReturnNode ( CfgScope scope , ReturnKind kind ) {
118+ exists ( ReturningNode ret |
119+ ret .( NodeImpl ) .getCfgScope ( ) = scope and
120+ ret .getKind ( ) = kind
121+ )
122+ } or
117123 TSsaDefinitionNode ( Ssa:: Definition def ) or
118124 TNormalParameterNode ( Parameter p ) { not p instanceof BlockParameter } or
119125 TSelfParameterNode ( MethodBase m ) or
@@ -140,14 +146,12 @@ private module Cached {
140146 TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or TSummaryParameterNode ;
141147
142148 /**
143- * This is the local flow predicate that is used as a building block in global
144- * data flow. It excludes SSA flow through instance fields, as flow through fields
145- * is handled by the global data-flow library, but includes various other steps
146- * that are only relevant for global flow.
149+ * This is the local flow predicate that is shared between local data flow
150+ * and global data flow.
147151 */
148152 cached
149- predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
150- exists ( Ssa :: Definition def | LocalFlow:: localSsaFlowStep ( def , nodeFrom , nodeTo ) )
153+ predicate simpleLocalFlowStepCommon ( Node nodeFrom , Node nodeTo ) {
154+ LocalFlow:: localSsaFlowStep ( _ , nodeFrom , nodeTo )
151155 or
152156 nodeTo .( ParameterNode ) .getParameter ( ) .( OptionalParameter ) .getDefaultValue ( ) =
153157 nodeFrom .asExpr ( ) .getExpr ( )
@@ -186,12 +190,39 @@ private module Cached {
186190 ) and
187191 nodeFrom .asExpr ( ) = for .getValue ( )
188192 )
193+ }
194+
195+ /**
196+ * This is the local flow predicate that is used as a building block in global
197+ * data flow. It excludes SSA flow through instance fields, as flow through fields
198+ * is handled by the global data-flow library, but includes various other steps
199+ * that are only relevant for global flow.
200+ */
201+ cached
202+ predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
203+ simpleLocalFlowStepCommon ( nodeFrom , nodeTo )
204+ or
205+ nodeTo .( SynthReturnNode ) .getAnInput ( ) = nodeFrom
189206 or
190207 FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom , nodeTo , true )
191208 }
192209
193210 cached
194- predicate isLocalSourceNode ( Node n ) { not simpleLocalFlowStep + ( any ( ExprNode e ) , n ) }
211+ predicate isLocalSourceNode ( Node n ) {
212+ n instanceof ParameterNode
213+ or
214+ // This case should not be needed once we have proper use-use flow
215+ // for `self`. At that point, the `self`s returned by `trackInstance`
216+ // in `DataFlowDispatch.qll` should refer to the post-update node,
217+ // and we can remove this case.
218+ n instanceof SelfArgumentNode
219+ or
220+ not simpleLocalFlowStepCommon + ( any ( Node e |
221+ e instanceof ExprNode
222+ or
223+ e instanceof ParameterNode
224+ ) , n )
225+ }
195226
196227 cached
197228 newtype TContent = TTodoContent ( ) // stub
@@ -208,6 +239,8 @@ predicate nodeIsHidden(Node n) {
208239 n instanceof SummaryNode
209240 or
210241 n instanceof SummaryParameterNode
242+ or
243+ n instanceof SynthReturnNode
211244}
212245
213246/** An SSA definition, viewed as a node in a data flow graph. */
@@ -234,7 +267,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
234267 * `ControlFlow::Node`s.
235268 */
236269class ReturningStatementNode extends NodeImpl , TReturningNode {
237- private CfgNodes:: ReturningCfgNode n ;
270+ CfgNodes:: ReturningCfgNode n ;
238271
239272 ReturningStatementNode ( ) { this = TReturningNode ( n ) }
240273
@@ -436,6 +469,12 @@ private module ArgumentNodes {
436469
437470import ArgumentNodes
438471
472+ /** A data-flow node that represents a value syntactically returned by a callable. */
473+ abstract class ReturningNode extends Node {
474+ /** Gets the kind of this return node. */
475+ abstract ReturnKind getKind ( ) ;
476+ }
477+
439478/** A data-flow node that represents a value returned by a callable. */
440479abstract class ReturnNode extends Node {
441480 /** Gets the kind of this return node. */
@@ -463,11 +502,9 @@ private module ReturnNodes {
463502 * A data-flow node that represents an expression returned by a callable,
464503 * either using an explict `return` statement or as the expression of a method body.
465504 */
466- class ExplicitReturnNode extends ReturnNode , ReturningStatementNode {
467- private CfgNodes:: ReturningCfgNode n ;
468-
505+ class ExplicitReturnNode extends ReturningNode , ReturningStatementNode {
469506 ExplicitReturnNode ( ) {
470- isValid ( this . getReturningNode ( ) ) and
507+ isValid ( n ) and
471508 n .getASuccessor ( ) .( CfgNodes:: AnnotatedExitNode ) .isNormal ( ) and
472509 n .getScope ( ) instanceof Callable
473510 }
@@ -479,7 +516,7 @@ private module ReturnNodes {
479516 }
480517 }
481518
482- class ExprReturnNode extends ReturnNode , ExprNode {
519+ class ExprReturnNode extends ReturningNode , ExprNode {
483520 ExprReturnNode ( ) {
484521 this .getExprNode ( ) .getASuccessor ( ) .( CfgNodes:: AnnotatedExitNode ) .isNormal ( ) and
485522 this .( NodeImpl ) .getCfgScope ( ) instanceof Callable
@@ -488,6 +525,34 @@ private module ReturnNodes {
488525 override ReturnKind getKind ( ) { result instanceof NormalReturnKind }
489526 }
490527
528+ /**
529+ * A synthetic data-flow node for joining flow from different syntactic
530+ * returns into a single node.
531+ *
532+ * This node only exists to avoid computing the product of a large fan-in
533+ * with a large fan-out.
534+ */
535+ class SynthReturnNode extends NodeImpl , ReturnNode , TSynthReturnNode {
536+ private CfgScope scope ;
537+ private ReturnKind kind ;
538+
539+ SynthReturnNode ( ) { this = TSynthReturnNode ( scope , kind ) }
540+
541+ /** Get a syntactic return node that flows into this synthetic node. */
542+ ReturningNode getAnInput ( ) {
543+ result .( NodeImpl ) .getCfgScope ( ) = scope and
544+ result .getKind ( ) = kind
545+ }
546+
547+ override ReturnKind getKind ( ) { result = kind }
548+
549+ override CfgScope getCfgScope ( ) { result = scope }
550+
551+ override Location getLocationImpl ( ) { result = scope .getLocation ( ) }
552+
553+ override string toStringImpl ( ) { result = "return " + kind + " in " + scope }
554+ }
555+
491556 private class SummaryReturnNode extends SummaryNode , ReturnNode {
492557 private ReturnKind rk ;
493558
@@ -631,7 +696,7 @@ private import PostUpdateNodes
631696
632697/** A node that performs a type cast. */
633698class CastNode extends Node {
634- CastNode ( ) { none ( ) }
699+ CastNode ( ) { this instanceof ReturningNode }
635700}
636701
637702class DataFlowExpr = CfgNodes:: ExprCfgNode ;
0 commit comments