diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/AbstractPropertiesImpl.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/AbstractPropertiesImpl.qll index f90177f737d7..6d86e7ea3f25 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/AbstractPropertiesImpl.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/AbstractPropertiesImpl.qll @@ -47,9 +47,8 @@ AbstractValue getAnInitialPropertyValue(DefiniteAbstractValue baseVal, string pr result = p.getInit().analyze().getALocalValue() ) or - // `f.prototype` for functions `f` that are instantiated + // `f.prototype` for functions `f` propertyName = "prototype" and - baseVal = any(NewExpr ne).getCallee().analyze().getALocalValue() and result = TAbstractInstance(baseVal) } diff --git a/javascript/ql/test/library-tests/CallGraphs/protoclass.js b/javascript/ql/test/library-tests/CallGraphs/protoclass.js new file mode 100644 index 000000000000..61978ee721a1 --- /dev/null +++ b/javascript/ql/test/library-tests/CallGraphs/protoclass.js @@ -0,0 +1,15 @@ +import * as dummy from 'dummy'; + +function F() { + this.init(); +} + +F.prototype.init = function() { + this.method(); + let m = this.method.bind(this); + m(); +}; + +F.prototype.method = function() {}; + +export default F; diff --git a/javascript/ql/test/library-tests/CallGraphs/tests.expected b/javascript/ql/test/library-tests/CallGraphs/tests.expected index b3a63a1726d2..ec4f9c8e65ad 100644 --- a/javascript/ql/test/library-tests/CallGraphs/tests.expected +++ b/javascript/ql/test/library-tests/CallGraphs/tests.expected @@ -12,6 +12,10 @@ test_isUncertain | n.js:2:1:2:5 | m.f() | | n.js:4:10:4:24 | require('./m2') | | n.js:5:1:5:6 | m2.f() | +| protoclass.js:4:3:4:13 | this.init() | +| protoclass.js:8:3:8:15 | this.method() | +| protoclass.js:9:11:9:32 | this.me ... d(this) | +| protoclass.js:10:3:10:5 | m() | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | | reflection.js:8:1:8:25 | add.app ... 3, 19]) | | tst.js:6:1:6:3 | f() | @@ -86,6 +90,18 @@ test_getAFunctionValue | m.js:3:1:3:16 | module.exports.f | m.js:1:13:1:25 | function() {} | | n.js:2:1:2:3 | m.f | m.js:1:13:1:25 | function() {} | | n.js:5:1:5:4 | m2.f | m2.js:2:6:2:18 | function() {} | +| protoclass.js:3:1:5:1 | functio ... it();\\n} | protoclass.js:3:1:5:1 | functio ... it();\\n} | +| protoclass.js:3:10:3:10 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} | +| protoclass.js:4:3:4:11 | this.init | protoclass.js:7:20:11:1 | functio ... m();\\n} | +| protoclass.js:7:1:7:1 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} | +| protoclass.js:7:1:11:1 | F.proto ... m();\\n} | protoclass.js:7:20:11:1 | functio ... m();\\n} | +| protoclass.js:7:20:11:1 | functio ... m();\\n} | protoclass.js:7:20:11:1 | functio ... m();\\n} | +| protoclass.js:8:3:8:13 | this.method | protoclass.js:13:22:13:34 | function() {} | +| protoclass.js:9:11:9:21 | this.method | protoclass.js:13:22:13:34 | function() {} | +| protoclass.js:13:1:13:1 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} | +| protoclass.js:13:1:13:34 | F.proto ... on() {} | protoclass.js:13:22:13:34 | function() {} | +| protoclass.js:13:22:13:34 | function() {} | protoclass.js:13:22:13:34 | function() {} | +| protoclass.js:15:16:15:16 | F | protoclass.js:3:1:5:1 | functio ... it();\\n} | | reflection.js:1:1:3:1 | functio ... x+y;\\n} | reflection.js:1:1:3:1 | functio ... x+y;\\n} | | reflection.js:5:3:5:5 | add | reflection.js:1:1:3:1 | functio ... x+y;\\n} | | reflection.js:5:3:5:39 | add.app ... n 56; } | reflection.js:5:15:5:39 | functio ... n 56; } | @@ -176,6 +192,7 @@ test_getArgument | es2015.js:36:1:36:17 | sum(1, ...[2], 3) | 0 | es2015.js:36:5:36:5 | 1 | | n.js:1:9:1:22 | require('./m') | 0 | n.js:1:17:1:21 | './m' | | n.js:4:10:4:24 | require('./m2') | 0 | n.js:4:18:4:23 | './m2' | +| protoclass.js:9:11:9:32 | this.me ... d(this) | 0 | protoclass.js:9:28:9:31 | this | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | 0 | reflection.js:7:10:7:13 | null | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | 1 | reflection.js:7:16:7:17 | 23 | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | 2 | reflection.js:7:20:7:21 | 19 | @@ -207,6 +224,10 @@ test_getNumArgument | n.js:2:1:2:5 | m.f() | 0 | | n.js:4:10:4:24 | require('./m2') | 1 | | n.js:5:1:5:6 | m2.f() | 0 | +| protoclass.js:4:3:4:13 | this.init() | 0 | +| protoclass.js:8:3:8:15 | this.method() | 0 | +| protoclass.js:9:11:9:32 | this.me ... d(this) | 1 | +| protoclass.js:10:3:10:5 | m() | 0 | | reflection.js:4:5:4:12 | sneaky() | 0 | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | 3 | | reflection.js:7:1:7:22 | reflective call | 2 | @@ -252,6 +273,10 @@ test_isIncomplete | n.js:2:1:2:5 | m.f() | | n.js:4:10:4:24 | require('./m2') | | n.js:5:1:5:6 | m2.f() | +| protoclass.js:4:3:4:13 | this.init() | +| protoclass.js:8:3:8:15 | this.method() | +| protoclass.js:9:11:9:32 | this.me ... d(this) | +| protoclass.js:10:3:10:5 | m() | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | | reflection.js:8:1:8:25 | add.app ... 3, 19]) | | tst.js:6:1:6:3 | f() | @@ -295,6 +320,10 @@ test_getCalleeNode | n.js:2:1:2:5 | m.f() | n.js:2:1:2:3 | m.f | | n.js:4:10:4:24 | require('./m2') | n.js:4:10:4:16 | require | | n.js:5:1:5:6 | m2.f() | n.js:5:1:5:4 | m2.f | +| protoclass.js:4:3:4:13 | this.init() | protoclass.js:4:3:4:11 | this.init | +| protoclass.js:8:3:8:15 | this.method() | protoclass.js:8:3:8:13 | this.method | +| protoclass.js:9:11:9:32 | this.me ... d(this) | protoclass.js:9:11:9:26 | this.method.bind | +| protoclass.js:10:3:10:5 | m() | protoclass.js:10:3:10:3 | m | | reflection.js:4:5:4:12 | sneaky() | reflection.js:4:5:4:10 | sneaky | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:1:7:8 | add.call | | reflection.js:7:1:7:22 | reflective call | reflection.js:7:1:7:3 | add | @@ -334,6 +363,7 @@ test_getLastArgument | es2015.js:27:5:27:23 | console.log(this.x) | es2015.js:27:17:27:22 | this.x | | n.js:1:9:1:22 | require('./m') | n.js:1:17:1:21 | './m' | | n.js:4:10:4:24 | require('./m2') | n.js:4:18:4:23 | './m2' | +| protoclass.js:9:11:9:32 | this.me ... d(this) | protoclass.js:9:28:9:31 | this | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:20:7:21 | 19 | | reflection.js:7:1:7:22 | reflective call | reflection.js:7:20:7:21 | 19 | | reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:17:8:24 | [23, 19] | @@ -349,6 +379,7 @@ test_getAnArgument | es2015.js:36:1:36:17 | sum(1, ...[2], 3) | es2015.js:36:16:36:16 | 3 | | n.js:1:9:1:22 | require('./m') | n.js:1:17:1:21 | './m' | | n.js:4:10:4:24 | require('./m2') | n.js:4:18:4:23 | './m2' | +| protoclass.js:9:11:9:32 | this.me ... d(this) | protoclass.js:9:28:9:31 | this | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:10:7:13 | null | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:16:7:17 | 23 | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:20:7:21 | 19 | @@ -377,6 +408,8 @@ test_getACallee | m.js:3:1:3:18 | module.exports.f() | m.js:1:13:1:25 | function() {} | | n.js:2:1:2:5 | m.f() | m.js:1:13:1:25 | function() {} | | n.js:5:1:5:6 | m2.f() | m2.js:2:6:2:18 | function() {} | +| protoclass.js:4:3:4:13 | this.init() | protoclass.js:7:20:11:1 | functio ... m();\\n} | +| protoclass.js:8:3:8:15 | this.method() | protoclass.js:13:22:13:34 | function() {} | | reflection.js:7:1:7:22 | reflective call | reflection.js:1:1:3:1 | functio ... x+y;\\n} | | reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:5:15:5:39 | functio ... n 56; } | | reflection.js:8:1:8:25 | reflective call | reflection.js:1:1:3:1 | functio ... x+y;\\n} | @@ -430,6 +463,10 @@ test_getCalleeName | n.js:2:1:2:5 | m.f() | f | | n.js:4:10:4:24 | require('./m2') | require | | n.js:5:1:5:6 | m2.f() | f | +| protoclass.js:4:3:4:13 | this.init() | init | +| protoclass.js:8:3:8:15 | this.method() | method | +| protoclass.js:9:11:9:32 | this.me ... d(this) | bind | +| protoclass.js:10:3:10:5 | m() | m | | reflection.js:4:5:4:12 | sneaky() | sneaky | | reflection.js:7:1:7:22 | add.cal ... 23, 19) | call | | reflection.js:8:1:8:25 | add.app ... 3, 19]) | apply | diff --git a/javascript/ql/test/library-tests/Flow/getAPrototype.expected b/javascript/ql/test/library-tests/Flow/getAPrototype.expected index 00fa7eb345c3..777245a661e9 100644 --- a/javascript/ql/test/library-tests/Flow/getAPrototype.expected +++ b/javascript/ql/test/library-tests/Flow/getAPrototype.expected @@ -1,6 +1,89 @@ +| ChatListScreen.js:3:1:5:1 | instance of function foo | ChatListScreen.js:3:1:5:1 | instance of function foo | +| a.js:3:8:5:1 | instance of function setX | a.js:3:8:5:1 | instance of function setX | +| a.js:15:1:17:1 | instance of function bump | a.js:15:1:17:1 | instance of function bump | +| amd2.js:1:8:3:1 | instance of anonymous function | amd2.js:1:8:3:1 | instance of anonymous function | +| amd3.js:1:24:4:1 | instance of anonymous function | amd3.js:1:24:4:1 | instance of anonymous function | +| amd.js:1:31:6:1 | instance of anonymous function | amd.js:1:31:6:1 | instance of anonymous function | +| arguments.js:1:2:3:1 | instance of anonymous function | arguments.js:1:2:3:1 | instance of anonymous function | +| arguments.js:5:2:8:1 | instance of anonymous function | arguments.js:5:2:8:1 | instance of anonymous function | +| arguments.js:10:2:14:1 | instance of anonymous function | arguments.js:10:2:14:1 | instance of anonymous function | +| arguments.js:16:2:19:1 | instance of anonymous function | arguments.js:16:2:19:1 | instance of anonymous function | +| arguments.js:22:2:28:1 | instance of anonymous function | arguments.js:22:2:28:1 | instance of anonymous function | +| arguments.js:30:2:33:1 | instance of anonymous function | arguments.js:30:2:33:1 | instance of anonymous function | +| c.js:3:1:5:1 | instance of function f | c.js:3:1:5:1 | instance of function f | +| destructuring.js:1:1:4:1 | instance of function f | destructuring.js:1:1:4:1 | instance of function f | | es2015.js:8:1:16:1 | instance of class Sub | es2015.js:1:11:6:1 | instance of class Sup | +| es2015.js:18:1:20:1 | instance of function f | es2015.js:18:1:20:1 | instance of function f | +| es2015.js:22:2:24:1 | instance of anonymous function | es2015.js:22:2:24:1 | instance of anonymous function | +| es2015.js:31:2:35:1 | instance of anonymous function | es2015.js:31:2:35:1 | instance of anonymous function | +| es2015.js:38:2:42:1 | instance of anonymous function | es2015.js:38:2:42:1 | instance of anonymous function | +| es2015.js:44:2:47:1 | instance of anonymous function | es2015.js:44:2:47:1 | instance of anonymous function | +| esLib.js:3:8:3:24 | instance of function foo | esLib.js:3:8:3:24 | instance of function foo | +| f.js:1:13:1:25 | instance of anonymous function | f.js:1:13:1:25 | instance of anonymous function | +| fundecls.js:1:2:10:1 | instance of anonymous function | fundecls.js:1:2:10:1 | instance of anonymous function | +| fundecls.js:4:3:4:17 | instance of function f | fundecls.js:4:3:4:17 | instance of function f | +| fundecls.js:8:5:8:19 | instance of function g | fundecls.js:8:5:8:19 | instance of function g | +| globals.html:7:8:10:7 | instance of anonymous function | globals.html:7:8:10:7 | instance of anonymous function | +| globals.html:16:8:19:7 | instance of anonymous function | globals.html:16:8:19:7 | instance of anonymous function | +| globals.html:22:7:22:21 | instance of function x | globals.html:22:7:22:21 | instance of function x | +| globals.html:26:23:26:69 | instance of anonymous function | globals.html:26:23:26:69 | instance of anonymous function | +| h.js:1:8:1:22 | instance of function f | h.js:1:8:1:22 | instance of function f | | instances.js:1:1:4:1 | instance of function A | instances.js:1:1:4:1 | instance of function A | +| instances.js:3:14:3:26 | instance of anonymous function | instances.js:3:14:3:26 | instance of anonymous function | +| instances.js:6:19:6:31 | instance of anonymous function | instances.js:6:19:6:31 | instance of anonymous function | | instances.js:13:1:13:18 | instance of function SubA | instances.js:1:1:4:1 | instance of function A | | instances.js:13:1:13:18 | instance of function SubA | instances.js:13:1:13:18 | instance of function SubA | +| n.js:1:1:1:15 | instance of function f | n.js:1:1:1:15 | instance of function f | +| n.js:2:1:2:15 | instance of function g | n.js:2:1:2:15 | instance of function g | +| nestedImport.js:9:1:12:1 | instance of function tst | nestedImport.js:9:1:12:1 | instance of function tst | +| nodeJsLib.js:1:18:1:43 | instance of function nodeJsModule | nodeJsLib.js:1:18:1:43 | instance of function nodeJsModule | +| nodeJsLib.js:3:15:3:37 | instance of function nodeJsFoo | nodeJsLib.js:3:15:3:37 | instance of function nodeJsFoo | +| objlit.js:2:9:2:21 | instance of anonymous function | objlit.js:2:9:2:21 | instance of anonymous function | +| objlit.js:4:8:4:20 | instance of method baz | objlit.js:4:8:4:20 | instance of method baz | +| objlit.js:10:2:12:1 | instance of anonymous function | objlit.js:10:2:12:1 | instance of anonymous function | +| objlit.js:11:11:11:23 | instance of anonymous function | objlit.js:11:11:11:23 | instance of anonymous function | +| objlit.js:23:2:48:1 | instance of anonymous function | objlit.js:23:2:48:1 | instance of anonymous function | +| objlit.js:41:10:41:22 | instance of anonymous function | objlit.js:41:10:41:22 | instance of anonymous function | | objlit.js:43:12:45:3 | object literal | file://:0:0:0:0 | null | | objlit.js:43:12:45:3 | object literal | objlit.js:33:12:40:3 | object literal | +| refinements.js:1:1:8:1 | instance of function f1 | refinements.js:1:1:8:1 | instance of function f1 | +| refinements.js:10:1:24:1 | instance of function f2 | refinements.js:10:1:24:1 | instance of function f2 | +| refinements.js:26:1:32:1 | instance of function f3 | refinements.js:26:1:32:1 | instance of function f3 | +| refinements.js:34:1:40:1 | instance of function f4 | refinements.js:34:1:40:1 | instance of function f4 | +| refinements.js:35:20:35:31 | instance of anonymous function | refinements.js:35:20:35:31 | instance of anonymous function | +| refinements.js:42:1:56:1 | instance of function f5 | refinements.js:42:1:56:1 | instance of function f5 | +| refinements.js:44:3:48:3 | instance of function inner | refinements.js:44:3:48:3 | instance of function inner | +| refinements.js:58:1:62:1 | instance of function f6 | refinements.js:58:1:62:1 | instance of function f6 | +| ts2.ts:1:10:1:22 | instance of anonymous function | ts2.ts:1:10:1:22 | instance of anonymous function | +| tst2.js:3:2:5:1 | instance of anonymous function | tst2.js:3:2:5:1 | instance of anonymous function | +| tst.js:1:1:39:1 | instance of function tst | tst.js:1:1:39:1 | instance of function tst | +| tst.js:15:12:15:23 | instance of function xd | tst.js:15:12:15:23 | instance of function xd | +| tst.js:42:1:44:1 | instance of function nonstrict | tst.js:42:1:44:1 | instance of function nonstrict | +| tst.js:46:1:49:1 | instance of function strict | tst.js:46:1:49:1 | instance of function strict | +| tst.js:51:1:57:1 | instance of function capturedFn | tst.js:51:1:57:1 | instance of function capturedFn | +| tst.js:52:3:52:24 | instance of function captured | tst.js:52:3:52:24 | instance of function captured | +| tst.js:53:3:55:3 | instance of function capturing | tst.js:53:3:55:3 | instance of function capturing | +| tst.js:59:2:62:1 | instance of anonymous function | tst.js:59:2:62:1 | instance of anonymous function | +| tst.js:64:2:66:1 | instance of anonymous function | tst.js:64:2:66:1 | instance of anonymous function | +| tst.js:68:2:70:1 | instance of anonymous function | tst.js:68:2:70:1 | instance of anonymous function | +| tst.js:72:2:76:1 | instance of function s | tst.js:72:2:76:1 | instance of function s | +| tst.js:78:2:82:1 | instance of anonymous function | tst.js:78:2:82:1 | instance of anonymous function | +| tst.js:84:2:87:1 | instance of anonymous function | tst.js:84:2:87:1 | instance of anonymous function | +| tst.js:89:2:92:1 | instance of anonymous function | tst.js:89:2:92:1 | instance of anonymous function | +| tst.js:94:2:104:1 | instance of anonymous function | tst.js:94:2:104:1 | instance of anonymous function | +| tst.js:95:3:97:3 | instance of function inner | tst.js:95:3:97:3 | instance of function inner | +| tst.js:106:2:109:1 | instance of anonymous function | tst.js:106:2:109:1 | instance of anonymous function | +| tst.js:111:1:113:1 | instance of function tst | tst.js:111:1:113:1 | instance of function tst | +| tst.js:115:2:132:1 | instance of anonymous function | tst.js:115:2:132:1 | instance of anonymous function | +| tst.js:116:12:118:3 | instance of anonymous function | tst.js:116:12:118:3 | instance of anonymous function | +| tst.js:119:12:121:3 | instance of anonymous function | tst.js:119:12:121:3 | instance of anonymous function | +| tst.js:122:12:124:3 | instance of anonymous function | tst.js:122:12:124:3 | instance of anonymous function | +| tst.js:125:12:125:24 | instance of anonymous function | tst.js:125:12:125:24 | instance of anonymous function | +| tst.js:126:12:130:3 | instance of anonymous function | tst.js:126:12:130:3 | instance of anonymous function | +| tst.js:131:12:131:37 | instance of anonymous function | tst.js:131:12:131:37 | instance of anonymous function | +| tst.js:134:1:142:1 | instance of function tst2 | tst.js:134:1:142:1 | instance of function tst2 | +| tst.js:144:1:149:1 | instance of function tst3 | tst.js:144:1:149:1 | instance of function tst3 | +| tst.js:151:1:162:1 | instance of function tst4 | tst.js:151:1:162:1 | instance of function tst4 | +| tst.js:164:1:172:1 | instance of function tst5 | tst.js:164:1:172:1 | instance of function tst5 | +| tst.ts:8:1:10:1 | instance of function setX | tst.ts:8:1:10:1 | instance of function setX | +| with.js:1:1:17:1 | instance of function f | with.js:1:1:17:1 | instance of function f |