@@ -14,47 +14,51 @@ import javascript
1414 * Holds if the receiver of `method` is bound.
1515 */
1616private predicate isBoundInMethod ( MethodDeclaration method ) {
17- exists ( DataFlow:: ThisNode thiz , MethodDeclaration bindingMethod |
17+ exists ( DataFlow:: ThisNode thiz , MethodDeclaration bindingMethod , string name |
1818 bindingMethod .getDeclaringClass ( ) = method .getDeclaringClass ( ) and
1919 not bindingMethod .isStatic ( ) and
20- thiz .getBinder ( ) .getAstNode ( ) = bindingMethod .getBody ( )
20+ thiz .getBinder ( ) .getAstNode ( ) = bindingMethod .getBody ( ) and
21+ name = method .getName ( )
2122 |
23+ // binding assignments: `this[x] = <expr>.bind(...)`
2224 exists ( DataFlow:: MethodCallNode bind , DataFlow:: PropWrite w |
23- // this[x] = <expr>.bind(...)
25+ not exists ( w .getPropertyName ( ) ) or // unknown name, assume everything is bound
26+ w .getPropertyName ( ) = name
27+ |
2428 w = thiz .getAPropertyWrite ( ) and
25- not exists ( w .getPropertyName ( ) ) and
2629 bind .getMethodName ( ) = "bind" and
2730 bind .flowsTo ( w .getRhs ( ) )
2831 )
2932 or
30- // require("auto-bind")(this)
33+ // library binders
3134 exists ( string mod |
3235 mod = "auto-bind" or
3336 mod = "react-autobind"
3437 |
3538 thiz .flowsTo ( DataFlow:: moduleImport ( mod ) .getACall ( ) .getArgument ( 0 ) )
36- )
37- or
38- exists ( string name | name = method .getName ( ) |
39- exists ( DataFlow:: MethodCallNode bind |
40- // this.<methodName> = <expr>.bind(...)
41- bind = thiz .getAPropertySource ( name ) and
42- bind .getMethodName ( ) = "bind"
43- )
39+ ) or
40+ // heuristic reflective binders
41+ exists ( DataFlow:: CallNode binder , string calleeName |
42+ (
43+ binder .( DataFlow:: MethodCallNode ) .getMethodName ( ) = calleeName or
44+ binder .getCalleeNode ( ) .asExpr ( ) .( VarAccess ) .getVariable ( ) .getName ( ) = calleeName
45+ ) and
46+ calleeName .regexpMatch ( "(?i).*bind.*" ) and
47+ thiz .flowsTo ( binder .getAnArgument ( ) ) and
48+ // exclude the binding assignments
49+ not thiz .getAPropertySource ( ) = binder
50+ |
51+ // `myBindAll(this)`
52+ binder .getNumArgument ( ) = 1
4453 or
45- exists ( DataFlow:: MethodCallNode bindAll |
46- bindAll .getMethodName ( ) = "bindAll" and
47- thiz .flowsTo ( bindAll .getArgument ( 0 ) )
48- |
49- // _.bindAll(this, <name1>)
50- bindAll .getArgument ( 1 ) .mayHaveStringValue ( name )
51- or
52- // _.bindAll(this, [<name1>, <name2>])
53- exists ( DataFlow:: ArrayCreationNode names |
54- names .flowsTo ( bindAll .getArgument ( 1 ) ) and
55- names .getAnElement ( ) .mayHaveStringValue ( name )
56- )
54+ // `myBindSome(this, [<name1>, <name2>])`
55+ exists ( DataFlow:: ArrayCreationNode names |
56+ names .flowsTo ( binder .getAnArgument ( ) ) and
57+ names .getAnElement ( ) .mayHaveStringValue ( name )
5758 )
59+ or
60+ // `myBindSome(this, <name1>, <name2>)`
61+ binder .getAnArgument ( ) .mayHaveStringValue ( name )
5862 )
5963 )
6064 or
@@ -66,10 +70,10 @@ private predicate isBoundInMethod(MethodDeclaration method) {
6670 ) and
6771 name .regexpMatch ( "(?i).*(bind|bound).*" )
6872 |
69- // @autobind
73+ // ` @autobind`
7074 decoration .( Identifier ) .getName ( ) = name
7175 or
72- // @action.bound
76+ // ` @action.bound`
7377 decoration .( PropAccess ) .getPropertyName ( ) = name
7478 )
7579}
0 commit comments