Skip to content

Commit 412f3b0

Browse files
committed
JS: API graph support for accessors (and classes)
1 parent add3610 commit 412f3b0

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

javascript/ql/lib/semmle/javascript/ApiGraphs.qll

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,12 +538,36 @@ module API {
538538
or
539539
lbl = Label::promisedError() and
540540
PromiseFlow::storeStep(rhs, pred, Promises::errorProp())
541+
or
542+
// The return-value of a getter G counts as a definition of property G
543+
// (Ordinary methods and properties are handled as PropWrite nodes)
544+
exists(string name | lbl = Label::member(name) |
545+
rhs = pred.(DataFlow::ObjectLiteralNode).getPropertyGetter(name).getAReturn()
546+
or
547+
rhs =
548+
pred.(DataFlow::ClassNode)
549+
.getStaticMember(name, DataFlow::MemberKind::getter())
550+
.getAReturn()
551+
)
552+
or
553+
// If `new C()` escapes, generate edges to its instance members
554+
exists(DataFlow::ClassNode cls, string name |
555+
pred = cls.getAClassReference().getAnInstantiation() and
556+
lbl = Label::member(name)
557+
|
558+
rhs = cls.getInstanceMethod(name)
559+
or
560+
rhs = cls.getInstanceMember(name, DataFlow::MemberKind::getter()).getAReturn()
561+
)
541562
)
542563
or
543564
exists(DataFlow::ClassNode cls, string name |
544565
base = MkClassInstance(cls) and
545-
lbl = Label::member(name) and
566+
lbl = Label::member(name)
567+
|
546568
rhs = cls.getInstanceMethod(name)
569+
or
570+
rhs = cls.getInstanceMember(name, DataFlow::MemberKind::getter()).getAReturn()
547571
)
548572
or
549573
exists(DataFlow::FunctionNode f |

javascript/ql/test/ApiGraphs/accessors/VerifyAssertions.expected

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import ApiGraphs.VerifyAssertions
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const foo = require('foo');
2+
3+
foo({
4+
myMethod(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
5+
console.log(x);
6+
}
7+
});
8+
9+
foo({
10+
get myMethod() {
11+
return function(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
12+
console.log(x)
13+
}
14+
}
15+
});
16+
17+
class C {
18+
static myMethod(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
19+
console.log(x);
20+
}
21+
}
22+
foo(C);
23+
24+
class D {
25+
myMethod(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
26+
console.log(x);
27+
}
28+
}
29+
foo(new D());
30+
31+
class E {
32+
get myMethod() {
33+
return function(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
34+
console.log(x);
35+
}
36+
}
37+
}
38+
foo(new E());
39+
40+
class F {
41+
static get myMethod() {
42+
return function(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
43+
console.log(x);
44+
}
45+
}
46+
}
47+
foo(F);
48+
49+
// Cases where the class is instantiated in `foo`:
50+
51+
class G {
52+
myMethod2(x) { /* use (parameter 0 (member myMethod2 (instance (parameter 0 (member exports (module foo)))))) */
53+
console.log(x);
54+
}
55+
}
56+
foo(G);
57+
58+
class H {
59+
get myMethod2() {
60+
return function (x) { /* use (parameter 0 (member myMethod2 (instance (parameter 0 (member exports (module foo)))))) */
61+
console.log(x);
62+
}
63+
}
64+
}
65+
foo(H);

0 commit comments

Comments
 (0)