@@ -983,73 +983,132 @@ module ClassNode {
983983}
984984
985985/**
986- * An invocation that is modeled as a partial function application.
986+ * A data flow node that performs a partial function application.
987987 *
988- * This contributes additional argument-passing flow edges that should be added to all data flow configurations.
988+ * Examples:
989+ * ```
990+ * fn.bind(this)
991+ * x.method.bind(x)
992+ * _.partial(fn, x, y, z)
993+ * ```
989994 */
990- abstract class AdditionalPartialInvokeNode extends DataFlow:: InvokeNode {
995+ class PartialInvokeNode extends DataFlow:: Node {
996+ PartialInvokeNode:: Range range ;
997+
998+ PartialInvokeNode ( ) { this = range }
999+
9911000 /**
9921001 * Holds if `argument` is passed as argument `index` to the function in `callback`.
9931002 */
994- abstract predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) ;
1003+ predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) {
1004+ range .isPartialArgument ( callback , argument , index )
1005+ }
1006+
1007+ /**
1008+ * Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound.
1009+ */
1010+ DataFlow:: SourceNode getBoundFunction ( DataFlow:: Node callback , int boundArgs ) {
1011+ result = range .getBoundFunction ( callback , boundArgs )
1012+ }
9951013
996- /** Gets the data flow node referring to the bound function, if such a node exists. */
997- DataFlow:: SourceNode getBoundFunction ( int boundArgs ) { none ( ) }
1014+ /**
1015+ * Gets the node holding the receiver to be passed to the bound function, if specified.
1016+ */
1017+ DataFlow:: Node getBoundReceiver ( ) { result = range .getBoundReceiver ( ) }
9981018}
9991019
1000- /**
1001- * A partial call through the built-in `Function.prototype.bind`.
1002- */
1003- private class BindPartialCall extends AdditionalPartialInvokeNode , DataFlow:: MethodCallNode {
1004- BindPartialCall ( ) { getMethodName ( ) = "bind" }
1020+ module PartialInvokeNode {
1021+ /**
1022+ * A data flow node that performs a partial function application.
1023+ */
1024+ abstract class Range extends DataFlow:: Node {
1025+ /**
1026+ * Holds if `argument` is passed as argument `index` to the function in `callback`.
1027+ */
1028+ predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) { none ( ) }
10051029
1006- override predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) {
1007- index >= 0 and
1008- callback = getReceiver ( ) and
1009- argument = getArgument ( index + 1 )
1010- }
1030+ /**
1031+ * Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound.
1032+ */
1033+ DataFlow:: SourceNode getBoundFunction ( DataFlow:: Node callback , int boundArgs ) { none ( ) }
10111034
1012- override DataFlow:: SourceNode getBoundFunction ( int boundArgs ) {
1013- boundArgs = getNumArgument ( ) - 1 and
1014- result = this
1035+ /**
1036+ * Gets the node holding the receiver to be passed to the bound function, if specified.
1037+ */
1038+ DataFlow:: Node getBoundReceiver ( ) { none ( ) }
10151039 }
1016- }
10171040
1018- /**
1019- * A partial call through `_.partial`.
1020- */
1021- private class LodashPartialCall extends AdditionalPartialInvokeNode {
1022- LodashPartialCall ( ) { this = LodashUnderscore:: member ( "partial" ) .getACall ( ) }
1041+ /**
1042+ * A partial call through the built-in `Function.prototype.bind`.
1043+ */
1044+ private class BindPartialCall extends PartialInvokeNode:: Range , DataFlow:: MethodCallNode {
1045+ BindPartialCall ( ) { getMethodName ( ) = "bind" }
1046+
1047+ override predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) {
1048+ index >= 0 and
1049+ callback = getReceiver ( ) and
1050+ argument = getArgument ( index + 1 )
1051+ }
10231052
1024- override predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) {
1025- index >= 0 and
1026- callback = getArgument ( 0 ) and
1027- argument = getArgument ( index + 1 )
1028- }
1053+ override DataFlow:: SourceNode getBoundFunction ( DataFlow:: Node callback , int boundArgs ) {
1054+ callback = getReceiver ( ) and
1055+ boundArgs = getNumArgument ( ) - 1 and
1056+ result = this
1057+ }
10291058
1030- override DataFlow:: SourceNode getBoundFunction ( int boundArgs ) {
1031- boundArgs = getNumArgument ( ) - 1 and
1032- result = this
1059+ override DataFlow:: Node getBoundReceiver ( ) {
1060+ result = getArgument ( 0 )
1061+ }
10331062 }
1034- }
10351063
1036- /**
1037- * A partial call through `ramda.partial`.
1038- */
1039- private class RamdaPartialCall extends AdditionalPartialInvokeNode {
1040- RamdaPartialCall ( ) { this = DataFlow:: moduleMember ( "ramda" , "partial" ) .getACall ( ) }
1064+ /**
1065+ * A partial call through `_.partial`.
1066+ */
1067+ private class LodashPartialCall extends PartialInvokeNode:: Range , DataFlow:: CallNode {
1068+ LodashPartialCall ( ) { this = LodashUnderscore:: member ( "partial" ) .getACall ( ) }
1069+
1070+ override predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) {
1071+ index >= 0 and
1072+ callback = getArgument ( 0 ) and
1073+ argument = getArgument ( index + 1 )
1074+ }
10411075
1042- private DataFlow:: ArrayCreationNode getArgumentsArray ( ) {
1043- result .flowsTo ( getArgument ( 1 ) )
1076+ override DataFlow:: SourceNode getBoundFunction ( DataFlow:: Node callback , int boundArgs ) {
1077+ callback = getReceiver ( ) and
1078+ boundArgs = getNumArgument ( ) - 1 and
1079+ result = this
1080+ }
10441081 }
10451082
1046- override predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) {
1047- callback = getArgument ( 0 ) and
1048- argument = getArgumentsArray ( ) .getElement ( index )
1049- }
1083+ /**
1084+ * A partial call through `ramda.partial`.
1085+ */
1086+ private class RamdaPartialCall extends PartialInvokeNode:: Range , DataFlow:: CallNode {
1087+ RamdaPartialCall ( ) { this = DataFlow:: moduleMember ( "ramda" , "partial" ) .getACall ( ) }
1088+
1089+ private DataFlow:: ArrayCreationNode getArgumentsArray ( ) {
1090+ result .flowsTo ( getArgument ( 1 ) )
1091+ }
10501092
1051- override DataFlow:: SourceNode getBoundFunction ( int boundArgs ) {
1052- boundArgs = getArgumentsArray ( ) .getSize ( ) and
1053- result = this
1093+ override predicate isPartialArgument ( DataFlow:: Node callback , DataFlow:: Node argument , int index ) {
1094+ callback = getArgument ( 0 ) and
1095+ argument = getArgumentsArray ( ) .getElement ( index )
1096+ }
1097+
1098+ override DataFlow:: SourceNode getBoundFunction ( DataFlow:: Node callback , int boundArgs ) {
1099+ callback = getArgument ( 0 ) and
1100+ boundArgs = getArgumentsArray ( ) .getSize ( ) and
1101+ result = this
1102+ }
10541103 }
10551104}
1105+
1106+ /**
1107+ * DEPRECATED. Subclasses should extend `PartialInvokeNode::Range` instead,
1108+ * and predicates should use `PartialInvokeNode` instead.
1109+ *
1110+ * An invocation that is modeled as a partial function application.
1111+ *
1112+ * This contributes additional argument-passing flow edges that should be added to all data flow configurations.
1113+ */
1114+ deprecated class AdditionalPartialInvokeNode = PartialInvokeNode:: Range ;
0 commit comments