@@ -318,6 +318,11 @@ module API {
318
318
Node getParameter ( int i ) {
319
319
Stages:: ApiStage:: ref ( ) and
320
320
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
+ )
321
326
}
322
327
323
328
/**
@@ -860,6 +865,23 @@ module API {
860
865
.getStaticMember ( name , DataFlow:: MemberKind:: getter ( ) )
861
866
.getAReturn ( )
862
867
)
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
+ )
863
885
)
864
886
or
865
887
exists ( DataFlow:: ClassNode cls , string name |
@@ -888,6 +910,11 @@ module API {
888
910
i = - 1 and lbl = Label:: receiver ( )
889
911
)
890
912
or
913
+ exists ( int i |
914
+ spreadArgumentPassing ( base , i , rhs ) and
915
+ lbl = Label:: spreadArgument ( i )
916
+ )
917
+ or
891
918
exists ( DataFlow:: SourceNode src , DataFlow:: PropWrite pw |
892
919
use ( base , src ) and pw = trackUseNode ( src ) .getAPropertyWrite ( ) and rhs = pw .getRhs ( )
893
920
|
@@ -931,6 +958,29 @@ module API {
931
958
)
932
959
}
933
960
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
+
934
984
/**
935
985
* Holds if `rhs` is the right-hand side of a definition of node `nd`.
936
986
*/
@@ -1579,6 +1629,9 @@ module API {
1579
1629
/** Gets the edge label for the receiver. */
1580
1630
LabelReceiver receiver ( ) { any ( ) }
1581
1631
1632
+ /** Gets the edge label for a spread argument passed at index `i`. */
1633
+ LabelSpreadArgument spreadArgument ( int i ) { result .getIndex ( ) = i }
1634
+
1582
1635
/** Gets the `return` edge label. */
1583
1636
LabelReturn return ( ) { any ( ) }
1584
1637
@@ -1628,6 +1681,7 @@ module API {
1628
1681
} or
1629
1682
MkLabelReceiver ( ) or
1630
1683
MkLabelReturn ( ) or
1684
+ MkLabelSpreadArgument ( int index ) { index = [ 0 .. 10 ] } or
1631
1685
MkLabelDecoratedClass ( ) or
1632
1686
MkLabelDecoratedMember ( ) or
1633
1687
MkLabelDecoratedParameter ( ) or
@@ -1743,6 +1797,21 @@ module API {
1743
1797
override string toString ( ) { result = "getReceiver()" }
1744
1798
}
1745
1799
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
+
1746
1815
/** A label for a function that is a wrapper around another function. */
1747
1816
class LabelForwardingFunction extends ApiLabel , MkLabelForwardingFunction {
1748
1817
override string toString ( ) { result = "getForwardingFunction()" }
0 commit comments