Skip to content

Commit 37b3a6e

Browse files
committed
JS: Add ClassNode.getStaticMember
1 parent cb898ae commit 37b3a6e

File tree

4 files changed

+66
-8
lines changed

4 files changed

+66
-8
lines changed

javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -898,17 +898,31 @@ class ClassNode extends DataFlow::SourceNode instanceof ClassNode::Range {
898898
*/
899899
FunctionNode getAnInstanceMember() { result = super.getAnInstanceMember(_) }
900900

901+
/**
902+
* Gets the static method, getter, or setter declared in this class with the given name and kind.
903+
*/
904+
FunctionNode getStaticMember(string name, MemberKind kind) {
905+
result = super.getStaticMember(name, kind)
906+
}
907+
901908
/**
902909
* Gets the static method declared in this class with the given name.
903910
*/
904-
FunctionNode getStaticMethod(string name) { result = super.getStaticMethod(name) }
911+
FunctionNode getStaticMethod(string name) {
912+
result = this.getStaticMember(name, MemberKind::method())
913+
}
914+
915+
/**
916+
* Gets a static method, getter, or setter declared in this class with the given kind.
917+
*/
918+
FunctionNode getAStaticMember(MemberKind kind) { result = super.getAStaticMember(kind) }
905919

906920
/**
907921
* Gets a static method declared in this class.
908922
*
909923
* The constructor is not considered a static method.
910924
*/
911-
FunctionNode getAStaticMethod() { result = super.getAStaticMethod() }
925+
FunctionNode getAStaticMethod() { result = this.getAStaticMember(MemberKind::method()) }
912926

913927
/**
914928
* Gets a dataflow node that refers to the superclass of this class.
@@ -1119,18 +1133,34 @@ module ClassNode {
11191133
abstract FunctionNode getAnInstanceMember(MemberKind kind);
11201134

11211135
/**
1136+
* Gets the static member of this class with the given name and kind.
1137+
*/
1138+
cached
1139+
abstract FunctionNode getStaticMember(string name, MemberKind kind);
1140+
1141+
/**
1142+
* DEPRECATED. Override `getStaticMember` instead.
1143+
*
11221144
* Gets the static method of this class with the given name.
11231145
*/
11241146
cached
1125-
abstract FunctionNode getStaticMethod(string name);
1147+
deprecated FunctionNode getStaticMethod(string name) { none() }
1148+
1149+
/**
1150+
* Gets a static member of this class of the given kind.
1151+
*/
1152+
cached
1153+
abstract FunctionNode getAStaticMember(MemberKind kind);
11261154

11271155
/**
1156+
* DEPRECATED. Override `getAStaticMember` instead.
1157+
*
11281158
* Gets a static method of this class.
11291159
*
11301160
* The constructor is not considered a static method.
11311161
*/
11321162
cached
1133-
abstract FunctionNode getAStaticMethod();
1163+
deprecated FunctionNode getAStaticMethod() { none() }
11341164

11351165
/**
11361166
* Gets a dataflow node representing a class to be used as the super-class
@@ -1186,23 +1216,27 @@ module ClassNode {
11861216
result = this.getConstructor().getReceiver().getAPropertySource()
11871217
}
11881218

1189-
override FunctionNode getStaticMethod(string name) {
1219+
override FunctionNode getStaticMember(string name, MemberKind kind) {
11901220
exists(MethodDeclaration method |
11911221
method = astNode.getMethod(name) and
11921222
method.isStatic() and
1223+
kind = MemberKind::of(method) and
11931224
result = method.getBody().flow()
11941225
)
11951226
or
1227+
kind.isMethod() and
11961228
result = this.getAPropertySource(name)
11971229
}
11981230

1199-
override FunctionNode getAStaticMethod() {
1231+
override FunctionNode getAStaticMember(MemberKind kind) {
12001232
exists(MethodDeclaration method |
12011233
method = astNode.getAMethod() and
12021234
method.isStatic() and
1235+
kind = MemberKind::of(method) and
12031236
result = method.getBody().flow()
12041237
)
12051238
or
1239+
kind.isMethod() and
12061240
result = this.getAPropertySource()
12071241
}
12081242

@@ -1300,9 +1334,15 @@ module ClassNode {
13001334
)
13011335
}
13021336

1303-
override FunctionNode getStaticMethod(string name) { result = this.getAPropertySource(name) }
1337+
override FunctionNode getStaticMember(string name, MemberKind kind) {
1338+
kind.isMethod() and
1339+
result = this.getAPropertySource(name)
1340+
}
13041341

1305-
override FunctionNode getAStaticMethod() { result = this.getAPropertySource() }
1342+
override FunctionNode getAStaticMember(MemberKind kind) {
1343+
kind.isMethod() and
1344+
result = this.getAPropertySource()
1345+
}
13061346

13071347
/**
13081348
* Gets a reference to the prototype of this class.

javascript/ql/test/library-tests/ClassNode/tests.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ getAReceiverNode
2424
| tst.js:23:1:23:15 | function D() {} | tst.js:25:13:25:12 | this |
2525
| tst.js:23:1:23:15 | function D() {} | tst.js:26:13:26:12 | this |
2626
| tst.js:23:1:23:15 | function D() {} | tst.js:27:4:27:3 | this |
27+
| tst.js:30:1:34:1 | class S ... x) {}\\n} | tst.js:30:21:30:20 | this |
2728
getFieldTypeAnnotation
2829
| fields.ts:1:1:3:1 | class B ... mber;\\n} | baseField | fields.ts:2:16:2:21 | number |
2930
| fields.ts:5:1:13:1 | class F ... > {};\\n} | x | fields.ts:6:27:6:32 | number |
@@ -53,6 +54,11 @@ instanceMethod
5354
| tst.js:15:1:15:15 | function B() {} | foo | tst.js:17:19:17:31 | function() {} | B |
5455
| tst.js:19:1:19:15 | function C() {} | bar | tst.js:21:19:21:31 | function() {} | C |
5556
| tst.js:23:1:23:15 | function D() {} | m | tst.js:27:4:27:8 | () {} | D |
57+
staticMember
58+
| tst.js:3:1:10:1 | class A ... () {}\\n} | staticMethod | method | tst.js:5:22:5:26 | () {} | A |
59+
| tst.js:30:1:34:1 | class S ... x) {}\\n} | getter | getter | tst.js:32:20:32:24 | () {} | StaticMembers |
60+
| tst.js:30:1:34:1 | class S ... x) {}\\n} | method | method | tst.js:31:16:31:20 | () {} | StaticMembers |
61+
| tst.js:30:1:34:1 | class S ... x) {}\\n} | setter | setter | tst.js:33:20:33:25 | (x) {} | StaticMembers |
5662
superClass
5763
| fields.ts:5:1:13:1 | class F ... > {};\\n} | fields.ts:1:1:3:1 | class B ... mber;\\n} | Foo | Base |
5864
| tst.js:13:1:13:21 | class A ... ds A {} | tst.js:3:1:10:1 | class A ... () {}\\n} | A2 | A |

javascript/ql/test/library-tests/ClassNode/tests.ql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ query predicate instanceMethod(
2424
cls.getInstanceMethod(name) = inst and clsName = cls.getName()
2525
}
2626

27+
query predicate staticMember(
28+
DataFlow::ClassNode cls, string name, string kind, DataFlow::FunctionNode inst, string clsName
29+
) {
30+
cls.getStaticMember(name, kind) = inst and clsName = cls.getName()
31+
}
32+
2733
query predicate superClass(
2834
DataFlow::ClassNode cls, DataFlow::ClassNode sup, string clsName, string supName
2935
) {

javascript/ql/test/library-tests/ClassNode/tst.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,9 @@ D.prototype = {
2626
set setter(x) {},
2727
m() {}
2828
}
29+
30+
class StaticMembers {
31+
static method() {}
32+
static get getter() {}
33+
static set setter(x) {}
34+
}

0 commit comments

Comments
 (0)