@@ -46,18 +46,19 @@ module LocalFlow {
4646 )
4747 }
4848
49+ /** Gets the SSA definition node corresponding to parameter `p`. */
50+ SsaDefinitionNode getParameterDefNode ( NamedParameter p ) {
51+ exists ( BasicBlock bb , int i |
52+ bb .getNode ( i ) .getNode ( ) = p .getDefiningAccess ( ) and
53+ result .getDefinition ( ) .definesAt ( _, bb , i )
54+ )
55+ }
56+
4957 /**
5058 * Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
51- * SSA definition `def.
59+ * SSA definition `def` .
5260 */
5361 predicate localSsaFlowStep ( Ssa:: Definition def , Node nodeFrom , Node nodeTo ) {
54- // Flow from parameter into SSA definition
55- exists ( BasicBlock bb , int i |
56- bb .getNode ( i ) .getNode ( ) =
57- nodeFrom .( ParameterNode ) .getParameter ( ) .( NamedParameter ) .getDefiningAccess ( ) and
58- nodeTo .( SsaDefinitionNode ) .getDefinition ( ) .definesAt ( _, bb , i )
59- )
60- or
6162 // Flow from assignment into SSA definition
6263 def .( Ssa:: WriteDefinition ) .assigns ( nodeFrom .asExpr ( ) ) and
6364 nodeTo .( SsaDefinitionNode ) .getDefinition ( ) = def
@@ -114,6 +115,12 @@ private module Cached {
114115 newtype TNode =
115116 TExprNode ( CfgNodes:: ExprCfgNode n ) or
116117 TReturningNode ( CfgNodes:: ReturningCfgNode n ) or
118+ TSynthReturnNode ( CfgScope scope , ReturnKind kind ) {
119+ exists ( ReturningNode ret |
120+ ret .( NodeImpl ) .getCfgScope ( ) = scope and
121+ ret .getKind ( ) = kind
122+ )
123+ } or
117124 TSsaDefinitionNode ( Ssa:: Definition def ) or
118125 TNormalParameterNode ( Parameter p ) { not p instanceof BlockParameter } or
119126 TSelfParameterNode ( MethodBase m ) or
@@ -139,21 +146,14 @@ private module Cached {
139146 class TParameterNode =
140147 TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or TSummaryParameterNode ;
141148
142- /**
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.
147- */
148- cached
149- predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
150- exists ( Ssa:: Definition def | LocalFlow:: localSsaFlowStep ( def , nodeFrom , nodeTo ) )
151- or
152- nodeTo .( ParameterNode ) .getParameter ( ) .( OptionalParameter ) .getDefaultValue ( ) =
153- nodeFrom .asExpr ( ) .getExpr ( )
149+ private predicate defaultValueFlow ( NamedParameter p , ExprNode e ) {
150+ p .( OptionalParameter ) .getDefaultValue ( ) = e .getExprNode ( ) .getExpr ( )
154151 or
155- nodeTo .( ParameterNode ) .getParameter ( ) .( KeywordParameter ) .getDefaultValue ( ) =
156- nodeFrom .asExpr ( ) .getExpr ( )
152+ p .( KeywordParameter ) .getDefaultValue ( ) = e .getExprNode ( ) .getExpr ( )
153+ }
154+
155+ private predicate localFlowStepCommon ( Node nodeFrom , Node nodeTo ) {
156+ LocalFlow:: localSsaFlowStep ( _, nodeFrom , nodeTo )
157157 or
158158 nodeFrom .( SelfParameterNode ) .getMethod ( ) = nodeTo .asExpr ( ) .getExpr ( ) .getEnclosingCallable ( ) and
159159 nodeTo .asExpr ( ) .getExpr ( ) instanceof Self
@@ -186,12 +186,66 @@ private module Cached {
186186 ) and
187187 nodeFrom .asExpr ( ) = for .getValue ( )
188188 )
189+ }
190+
191+ /**
192+ * This is the local flow predicate that is used as a building block in global
193+ * data flow.
194+ */
195+ cached
196+ predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
197+ localFlowStepCommon ( nodeFrom , nodeTo )
198+ or
199+ defaultValueFlow ( nodeTo .( ParameterNode ) .getParameter ( ) , nodeFrom )
200+ or
201+ nodeTo = LocalFlow:: getParameterDefNode ( nodeFrom .( ParameterNode ) .getParameter ( ) )
202+ or
203+ nodeTo .( SynthReturnNode ) .getAnInput ( ) = nodeFrom
189204 or
190205 FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom , nodeTo , true )
191206 }
192207
208+ /** This is the local flow predicate that is exposed. */
193209 cached
194- predicate isLocalSourceNode ( Node n ) { not simpleLocalFlowStep + ( any ( ExprNode e ) , n ) }
210+ predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) {
211+ localFlowStepCommon ( nodeFrom , nodeTo )
212+ or
213+ defaultValueFlow ( nodeTo .( ParameterNode ) .getParameter ( ) , nodeFrom )
214+ or
215+ nodeTo = LocalFlow:: getParameterDefNode ( nodeFrom .( ParameterNode ) .getParameter ( ) )
216+ or
217+ // Simple flow through library code is included in the exposed local
218+ // step relation, even though flow is technically inter-procedural
219+ FlowSummaryImpl:: Private:: Steps:: summaryThroughStep ( nodeFrom , nodeTo , true )
220+ }
221+
222+ /** This is the local flow predicate that is used in type tracking. */
223+ cached
224+ predicate localFlowStepTypeTracker ( Node nodeFrom , Node nodeTo ) {
225+ localFlowStepCommon ( nodeFrom , nodeTo )
226+ or
227+ exists ( NamedParameter p |
228+ defaultValueFlow ( p , nodeFrom ) and
229+ nodeTo = LocalFlow:: getParameterDefNode ( p )
230+ )
231+ }
232+
233+ cached
234+ predicate isLocalSourceNode ( Node n ) {
235+ n instanceof ParameterNode
236+ or
237+ // This case should not be needed once we have proper use-use flow
238+ // for `self`. At that point, the `self`s returned by `trackInstance`
239+ // in `DataFlowDispatch.qll` should refer to the post-update node,
240+ // and we can remove this case.
241+ n instanceof SelfArgumentNode
242+ or
243+ not localFlowStepTypeTracker + ( any ( Node e |
244+ e instanceof ExprNode
245+ or
246+ e instanceof ParameterNode
247+ ) , n )
248+ }
195249
196250 cached
197251 newtype TContent = TTodoContent ( ) // stub
@@ -208,6 +262,8 @@ predicate nodeIsHidden(Node n) {
208262 n instanceof SummaryNode
209263 or
210264 n instanceof SummaryParameterNode
265+ or
266+ n instanceof SynthReturnNode
211267}
212268
213269/** An SSA definition, viewed as a node in a data flow graph. */
@@ -234,7 +290,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
234290 * `ControlFlow::Node`s.
235291 */
236292class ReturningStatementNode extends NodeImpl , TReturningNode {
237- private CfgNodes:: ReturningCfgNode n ;
293+ CfgNodes:: ReturningCfgNode n ;
238294
239295 ReturningStatementNode ( ) { this = TReturningNode ( n ) }
240296
@@ -436,6 +492,12 @@ private module ArgumentNodes {
436492
437493import ArgumentNodes
438494
495+ /** A data-flow node that represents a value syntactically returned by a callable. */
496+ abstract class ReturningNode extends Node {
497+ /** Gets the kind of this return node. */
498+ abstract ReturnKind getKind ( ) ;
499+ }
500+
439501/** A data-flow node that represents a value returned by a callable. */
440502abstract class ReturnNode extends Node {
441503 /** Gets the kind of this return node. */
@@ -463,11 +525,9 @@ private module ReturnNodes {
463525 * A data-flow node that represents an expression returned by a callable,
464526 * either using an explict `return` statement or as the expression of a method body.
465527 */
466- class ExplicitReturnNode extends ReturnNode , ReturningStatementNode {
467- private CfgNodes:: ReturningCfgNode n ;
468-
528+ class ExplicitReturnNode extends ReturningNode , ReturningStatementNode {
469529 ExplicitReturnNode ( ) {
470- isValid ( this . getReturningNode ( ) ) and
530+ isValid ( n ) and
471531 n .getASuccessor ( ) .( CfgNodes:: AnnotatedExitNode ) .isNormal ( ) and
472532 n .getScope ( ) instanceof Callable
473533 }
@@ -479,7 +539,7 @@ private module ReturnNodes {
479539 }
480540 }
481541
482- class ExprReturnNode extends ReturnNode , ExprNode {
542+ class ExprReturnNode extends ReturningNode , ExprNode {
483543 ExprReturnNode ( ) {
484544 this .getExprNode ( ) .getASuccessor ( ) .( CfgNodes:: AnnotatedExitNode ) .isNormal ( ) and
485545 this .( NodeImpl ) .getCfgScope ( ) instanceof Callable
@@ -488,6 +548,34 @@ private module ReturnNodes {
488548 override ReturnKind getKind ( ) { result instanceof NormalReturnKind }
489549 }
490550
551+ /**
552+ * A synthetic data-flow node for joining flow from different syntactic
553+ * returns into a single node.
554+ *
555+ * This node only exists to avoid computing the product of a large fan-in
556+ * with a large fan-out.
557+ */
558+ class SynthReturnNode extends NodeImpl , ReturnNode , TSynthReturnNode {
559+ private CfgScope scope ;
560+ private ReturnKind kind ;
561+
562+ SynthReturnNode ( ) { this = TSynthReturnNode ( scope , kind ) }
563+
564+ /** Gets a syntactic return node that flows into this synthetic node. */
565+ ReturningNode getAnInput ( ) {
566+ result .( NodeImpl ) .getCfgScope ( ) = scope and
567+ result .getKind ( ) = kind
568+ }
569+
570+ override ReturnKind getKind ( ) { result = kind }
571+
572+ override CfgScope getCfgScope ( ) { result = scope }
573+
574+ override Location getLocationImpl ( ) { result = scope .getLocation ( ) }
575+
576+ override string toStringImpl ( ) { result = "return " + kind + " in " + scope }
577+ }
578+
491579 private class SummaryReturnNode extends SummaryNode , ReturnNode {
492580 private ReturnKind rk ;
493581
@@ -631,7 +719,7 @@ private import PostUpdateNodes
631719
632720/** A node that performs a type cast. */
633721class CastNode extends Node {
634- CastNode ( ) { none ( ) }
722+ CastNode ( ) { this instanceof ReturningNode }
635723}
636724
637725class DataFlowExpr = CfgNodes:: ExprCfgNode ;
0 commit comments