@@ -112,47 +112,43 @@ class AnalyzedVarDef extends VarDef {
112112}
113113
114114/**
115- * Flow analysis for simple IIFE parameters.
116- */
117- private class AnalyzedIIFEParameter extends AnalyzedVarDef , @vardecl {
118- AnalyzedIIFEParameter ( ) {
119- exists ( ImmediatelyInvokedFunctionExpr iife , int parmIdx |
120- this = iife .getParameter ( parmIdx ) |
121- // we cannot track flow into rest parameters...
122- not this .( Parameter ) .isRestParameter ( ) and
123- // ...nor flow out of spread arguments
124- exists ( int argIdx | argIdx = parmIdx + iife .getArgumentOffset ( ) |
125- not iife .isSpreadArgument ( [ 0 ..argIdx ] )
126- )
115+ * Flow analysis for simple parameters of selected functions.
116+ */
117+ private class AnalyzedParameter extends AnalyzedVarDef , @vardecl {
118+ AnalyzedParameter ( ) {
119+ exists ( FunctionWithAnalyzedParameters f , int parmIdx |
120+ this = f .getParameter ( parmIdx ) |
121+ // we cannot track flow into rest parameters
122+ not this .( Parameter ) .isRestParameter ( )
127123 )
128124 }
129125
130- /** Gets the IIFE this is a parameter of. */
131- ImmediatelyInvokedFunctionExpr getIIFE ( ) {
126+ /** Gets the function this is a parameter of. */
127+ FunctionWithAnalyzedParameters getFunction ( ) {
132128 this = result .getAParameter ( )
133129 }
134130
135131 override DataFlow:: AnalyzedNode getRhs ( ) {
136- getIIFE ( ) .argumentPassing ( this , result .asExpr ( ) ) or
132+ getFunction ( ) .argumentPassing ( this , result .asExpr ( ) ) or
137133 result = this .( Parameter ) .getDefault ( ) .analyze ( )
138134 }
139135
140136 override AbstractValue getAnRhsValue ( ) {
141- result = AnalyzedVarDef .super .getAnRhsValue ( ) or
142- not getIIFE ( ) .argumentPassing ( this , _) and result = TAbstractUndefined ( )
137+ result = AnalyzedVarDef .super .getAnRhsValue ( )
138+ or
139+ not getFunction ( ) .mayReceiveArgument ( this ) and
140+ result = TAbstractUndefined ( )
143141 }
144142
145143 override predicate isIncomplete ( DataFlow:: Incompleteness cause ) {
146- exists ( ImmediatelyInvokedFunctionExpr iife | iife = getIIFE ( ) |
147- // if the IIFE has a name and that name is referenced, we conservatively
148- // assume that there may be other calls than the direct one
149- exists ( iife .getVariable ( ) .getAnAccess ( ) ) and cause = "call" or
150- // if the IIFE is non-strict and its `arguments` object is accessed, we
151- // also assume that there may be other calls (through `arguments.callee`)
152- not iife .isStrict ( ) and
153- exists ( iife .getArgumentsVariable ( ) .getAnAccess ( ) ) and cause = "call"
144+ getFunction ( ) .isIncomplete ( cause ) or
145+ (
146+ not getFunction ( ) .argumentPassing ( this , _) and
147+ getFunction ( ) .mayReceiveArgument ( this ) and
148+ cause = "call"
154149 )
155150 }
151+
156152}
157153
158154/**
@@ -650,3 +646,82 @@ private class NamespaceExportVarFlow extends DataFlow::AnalyzedValueNode {
650646
651647 override AbstractValue getALocalValue ( ) { result = TIndefiniteAbstractValue ( "namespace" ) }
652648}
649+
650+ /**
651+ * A function with inter-procedural type inference for its parameters.
652+ */
653+ abstract class FunctionWithAnalyzedParameters extends Function {
654+
655+ /**
656+ * Holds if `p` is a parameter of this function and `arg` is
657+ * the corresponding argument.
658+ */
659+ abstract predicate argumentPassing ( SimpleParameter p , Expr arg ) ;
660+
661+ /**
662+ * Holds if `p` is a parameter of this function that may receive a value from an argument.
663+ */
664+ abstract predicate mayReceiveArgument ( Parameter p ) ;
665+
666+ /**
667+ * Holds if flow analysis results for the parameters may be incomplete
668+ * due to the given `cause`.
669+ */
670+ abstract predicate isIncomplete ( DataFlow:: Incompleteness cause ) ;
671+
672+ }
673+
674+ private abstract class CallWithAnalyzedParameters extends FunctionWithAnalyzedParameters {
675+
676+ /**
677+ * Gets an invocation of this function.
678+ */
679+ abstract DataFlow:: InvokeNode getAnInvocation ( ) ;
680+
681+ override predicate argumentPassing ( SimpleParameter p , Expr arg ) {
682+ exists ( DataFlow:: InvokeNode invk , int argIdx |
683+ invk = getAnInvocation ( ) |
684+ p = getParameter ( argIdx ) and not p .isRestParameter ( ) and
685+ arg = invk .getArgument ( argIdx ) .asExpr ( )
686+ )
687+ }
688+
689+ override predicate mayReceiveArgument ( Parameter p ) {
690+ exists ( DataFlow:: InvokeNode invk , int argIdx |
691+ invk = getAnInvocation ( ) and
692+ p = getParameter ( argIdx ) |
693+ exists ( invk .getArgument ( argIdx ) )
694+ or
695+ invk .asExpr ( ) .( InvokeExpr ) .isSpreadArgument ( [ 0 ..argIdx ] )
696+ )
697+ }
698+
699+ }
700+
701+ /**
702+ * Flow analysis for simple parameters of IIFEs.
703+ */
704+ private class IIFEWithAnalyzedParameters extends CallWithAnalyzedParameters {
705+
706+ ImmediatelyInvokedFunctionExpr iife ;
707+
708+ IIFEWithAnalyzedParameters ( ) {
709+ this = iife and
710+ iife .getInvocationKind ( ) = "direct"
711+ }
712+
713+ override DataFlow:: InvokeNode getAnInvocation ( ) {
714+ result = iife .getInvocation ( ) .flow ( )
715+ }
716+
717+ override predicate isIncomplete ( DataFlow:: Incompleteness cause ) {
718+ // if the IIFE has a name and that name is referenced, we conservatively
719+ // assume that there may be other calls than the direct one
720+ exists ( iife .getVariable ( ) .getAnAccess ( ) ) and cause = "call" or
721+ // if the IIFE is non-strict and its `arguments` object is accessed, we
722+ // also assume that there may be other calls (through `arguments.callee`)
723+ not iife .isStrict ( ) and
724+ exists ( iife .getArgumentsVariable ( ) .getAnAccess ( ) ) and cause = "call"
725+ }
726+
727+ }
0 commit comments