@@ -318,6 +318,11 @@ module API {
318318 Node getParameter ( int i ) {
319319 Stages:: ApiStage:: ref ( ) and
320320 result = this .getASuccessor ( Label:: parameter ( i ) )
321+ or
322+ exists ( int spreadIndex , string arrayProp |
323+ result = this .getASuccessor ( Label:: spreadArgument ( spreadIndex ) ) .getMember ( arrayProp ) and
324+ i = spreadIndex + arrayProp .toInt ( )
325+ )
321326 }
322327
323328 /**
@@ -860,6 +865,23 @@ module API {
860865 .getStaticMember ( name , DataFlow:: MemberKind:: getter ( ) )
861866 .getAReturn ( )
862867 )
868+ or
869+ // Handle rest parameters escaping into external code. For example:
870+ //
871+ // function foo(...rest) {
872+ // externalFunc(rest);
873+ // }
874+ //
875+ // Here, 'rest' reaches a def-node at the call to externalFunc, so we need to ensure
876+ // the arguments passed to 'foo' are stored in the 'rest' array.
877+ exists ( Function fun , DataFlow:: InvokeNode invoke , int argIndex , Parameter rest |
878+ fun .getRestParameter ( ) = rest and
879+ rest .flow ( ) = pred and
880+ invoke .getACallee ( ) = fun and
881+ invoke .getArgument ( argIndex ) = rhs and
882+ argIndex >= rest .getIndex ( ) and
883+ lbl = Label:: member ( ( argIndex - rest .getIndex ( ) ) .toString ( ) )
884+ )
863885 )
864886 or
865887 exists ( DataFlow:: ClassNode cls , string name |
@@ -888,6 +910,11 @@ module API {
888910 i = - 1 and lbl = Label:: receiver ( )
889911 )
890912 or
913+ exists ( int i |
914+ spreadArgumentPassing ( base , i , rhs ) and
915+ lbl = Label:: spreadArgument ( i )
916+ )
917+ or
891918 exists ( DataFlow:: SourceNode src , DataFlow:: PropWrite pw |
892919 use ( base , src ) and pw = trackUseNode ( src ) .getAPropertyWrite ( ) and rhs = pw .getRhs ( )
893920 |
@@ -931,6 +958,29 @@ module API {
931958 )
932959 }
933960
961+ pragma [ nomagic]
962+ private int firstSpreadIndex ( InvokeExpr expr ) {
963+ result = min ( int i | expr .getArgument ( i ) instanceof SpreadElement )
964+ }
965+
966+ pragma [ nomagic]
967+ private InvokeExpr getAnInvocationWithSpread ( DataFlow:: SourceNode node , int i ) {
968+ result = node .getAnInvocation ( ) .asExpr ( ) and
969+ i = firstSpreadIndex ( result )
970+ }
971+
972+ private predicate spreadArgumentPassing ( TApiNode base , int i , DataFlow:: Node spreadArray ) {
973+ exists (
974+ DataFlow:: Node use , DataFlow:: SourceNode pred , int bound , InvokeExpr invoke , int spreadPos
975+ |
976+ use ( base , use ) and
977+ pred = trackUseNode ( use , _, bound , "" ) and
978+ invoke = getAnInvocationWithSpread ( pred , spreadPos ) and
979+ spreadArray = invoke .getArgument ( spreadPos ) .( SpreadElement ) .getOperand ( ) .flow ( ) and
980+ i = bound + spreadPos
981+ )
982+ }
983+
934984 /**
935985 * Holds if `rhs` is the right-hand side of a definition of node `nd`.
936986 */
@@ -1579,6 +1629,9 @@ module API {
15791629 /** Gets the edge label for the receiver. */
15801630 LabelReceiver receiver ( ) { any ( ) }
15811631
1632+ /** Gets the edge label for a spread argument passed at index `i`. */
1633+ LabelSpreadArgument spreadArgument ( int i ) { result .getIndex ( ) = i }
1634+
15821635 /** Gets the `return` edge label. */
15831636 LabelReturn return ( ) { any ( ) }
15841637
@@ -1628,6 +1681,7 @@ module API {
16281681 } or
16291682 MkLabelReceiver ( ) or
16301683 MkLabelReturn ( ) or
1684+ MkLabelSpreadArgument ( int index ) { index = [ 0 .. 10 ] } or
16311685 MkLabelDecoratedClass ( ) or
16321686 MkLabelDecoratedMember ( ) or
16331687 MkLabelDecoratedParameter ( ) or
@@ -1743,6 +1797,21 @@ module API {
17431797 override string toString ( ) { result = "getReceiver()" }
17441798 }
17451799
1800+ /** A label representing an array passed as a spread argument at a given index. */
1801+ class LabelSpreadArgument extends ApiLabel , MkLabelSpreadArgument {
1802+ private int index ;
1803+
1804+ LabelSpreadArgument ( ) { this = MkLabelSpreadArgument ( index ) }
1805+
1806+ /** Gets the argument index at which the spread argument appears. */
1807+ int getIndex ( ) { result = index }
1808+
1809+ override string toString ( ) {
1810+ // Note: This refers to the internal edge that has no corresponding method on API::Node
1811+ result = "getSpreadArgument(" + index + ")"
1812+ }
1813+ }
1814+
17461815 /** A label for a function that is a wrapper around another function. */
17471816 class LabelForwardingFunction extends ApiLabel , MkLabelForwardingFunction {
17481817 override string toString ( ) { result = "getForwardingFunction()" }
0 commit comments