add support for private fields in classes

This commit is contained in:
Erik Krogh Kristensen
2020-01-29 13:06:45 +01:00
parent fb90c2ba52
commit b8834ffcad
9 changed files with 201 additions and 4 deletions

View File

@@ -0,0 +1,17 @@
import javascript
class Configuration extends DataFlow::Configuration {
Configuration() { this = "ClassDataFlowTestingConfig" }
override predicate isSource(DataFlow::Node source) {
source.getEnclosingExpr().(StringLiteral).getValue().toLowerCase() = "source"
}
override predicate isSink(DataFlow::Node sink) {
any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() = sink
}
}
query predicate dataflow(DataFlow::Node pred, DataFlow::Node succ) {
any(Configuration c).hasFlow(pred, succ)
}

View File

@@ -0,0 +1,9 @@
import javascript
query string getAccessModifier(DataFlow::PropRef ref, Expr prop) {
prop = ref.getPropertyNameExpr() and
if ref.isPrivateField() then
result = "Private"
else
result = "Public"
}

View File

@@ -0,0 +1,17 @@
(function () {
var source = "source";
class Foo {
#priv = source;
getPriv() {
return this.#priv;
}
getFalsePrivate() {
return this["#priv"]; // not the same field as above. But we currently don't distinguish private and "public" fields.
}
}
sink(new Foo().getPriv()); // NOT OK.
sink(new Foo().getFalsePrivate()); // OK [FP: Is FP because we do nothing special about dataflow for private fields.]
})();

View File

@@ -0,0 +1,22 @@
class Foo {
#privDecl = 3;
#if = "if"; // "keywords" are ok.
reads() {
var foo = this.#privUse;
var bar = this["#publicComputed"]
var baz = this.#if;
}
equals(o) {
return this.#privDecl === o.#privDecl;
}
writes() {
this.#privDecl = 4;
this["#public"] = 5;
}
#privSecond; // is a PropNode, not a PropRef. Doesn't matter.
["#publicField"] = 6;
}

View File

@@ -1,5 +1,9 @@
test_FieldInits
| dataflow.js:5:3:5:17 | #priv = source; | dataflow.js:5:11:5:16 | source |
| fields.js:3:3:3:8 | y = 42 | fields.js:3:7:3:8 | 42 |
| privateFields.js:2:2:2:15 | #privDecl = 3; | privateFields.js:2:14:2:14 | 3 |
| privateFields.js:3:2:3:12 | #if = "if"; | privateFields.js:3:8:3:11 | "if" |
| privateFields.js:21:2:21:22 | ["#publ ... "] = 6; | privateFields.js:21:21:21:21 | 6 |
test_ComputedMethods
| tst.js:3:3:3:56 | ["const ... r. */ } |
| tst.js:13:3:13:10 | [m]() {} |
@@ -15,9 +19,11 @@ test_ClassNodeStaticMethod
| points.js:20:1:33:1 | class C ... ;\\n }\\n} | className | points.js:30:19:32:3 | () {\\n ... t";\\n } |
| staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | constructor | staticConstructor.js:2:21:2:59 | () { re ... tor"; } |
test_ClassDefinitions
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} |
| fields.js:1:1:4:1 | class C ... = 42\\n} |
| points.js:1:1:18:1 | class P ... ;\\n }\\n} |
| points.js:20:1:33:1 | class C ... ;\\n }\\n} |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} |
| staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} |
| tst.js:1:9:4:1 | class { ... */ }\\n} |
| tst.js:6:1:8:1 | class B ... t); }\\n} |
@@ -25,17 +31,27 @@ test_ClassDefinitions
test_AccessorMethods
| points.js:7:3:9:3 | get dis ... y);\\n } |
test_Fields
| dataflow.js:5:3:5:17 | #priv = source; | dataflow.js:5:3:5:7 | #priv |
| fields.js:2:3:2:4 | x; | fields.js:2:3:2:3 | x |
| fields.js:3:3:3:8 | y = 42 | fields.js:3:3:3:3 | y |
| privateFields.js:2:2:2:15 | #privDecl = 3; | privateFields.js:2:2:2:10 | #privDecl |
| privateFields.js:3:2:3:12 | #if = "if"; | privateFields.js:3:2:3:4 | #if |
| privateFields.js:19:2:19:13 | #privSecond; | privateFields.js:19:2:19:12 | #privSecond |
| privateFields.js:21:2:21:22 | ["#publ ... "] = 6; | privateFields.js:21:3:21:16 | "#publicField" |
test_ClassDefinition_getName
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | Foo |
| fields.js:1:1:4:1 | class C ... = 42\\n} | C |
| points.js:1:1:18:1 | class P ... ;\\n }\\n} | Point |
| points.js:20:1:33:1 | class C ... ;\\n }\\n} | ColouredPoint |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | Foo |
| staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | MyClass |
| tst.js:1:9:4:1 | class { ... */ }\\n} | A |
| tst.js:6:1:8:1 | class B ... t); }\\n} | B |
| tst.js:11:1:14:1 | class C ... () {}\\n} | C |
test_MethodDefinitions
| dataflow.js:4:12:4:11 | constructor() {} | dataflow.js:4:12:4:11 | constructor | dataflow.js:4:12:4:11 | () {} | dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} |
| dataflow.js:6:3:8:3 | getPriv ... iv;\\n\\t\\t} | dataflow.js:6:3:6:9 | getPriv | dataflow.js:6:10:8:3 | () {\\n\\t\\t ... iv;\\n\\t\\t} | dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} |
| dataflow.js:10:3:12:3 | getFals ... . \\n\\t\\t} | dataflow.js:10:3:10:17 | getFalsePrivate | dataflow.js:10:18:12:3 | () {\\n\\t\\t ... . \\n\\t\\t} | dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} |
| fields.js:1:9:1:8 | constructor() {} | fields.js:1:9:1:8 | constructor | fields.js:1:9:1:8 | () {} | fields.js:1:1:4:1 | class C ... = 42\\n} |
| points.js:2:3:5:3 | constru ... y;\\n } | points.js:2:3:2:13 | constructor | points.js:2:14:5:3 | (x, y) ... y;\\n } | points.js:1:1:18:1 | class P ... ;\\n }\\n} |
| points.js:7:3:9:3 | get dis ... y);\\n } | points.js:7:7:7:10 | dist | points.js:7:11:9:3 | () {\\n ... y);\\n } | points.js:1:1:18:1 | class P ... ;\\n }\\n} |
@@ -44,6 +60,10 @@ test_MethodDefinitions
| points.js:21:3:24:3 | constru ... c;\\n } | points.js:21:3:21:13 | constructor | points.js:21:14:24:3 | (x, y, ... c;\\n } | points.js:20:1:33:1 | class C ... ;\\n }\\n} |
| points.js:26:3:28:3 | toStrin ... ur;\\n } | points.js:26:3:26:10 | toString | points.js:26:11:28:3 | () {\\n ... ur;\\n } | points.js:20:1:33:1 | class C ... ;\\n }\\n} |
| points.js:30:3:32:3 | static ... t";\\n } | points.js:30:10:30:18 | className | points.js:30:19:32:3 | () {\\n ... t";\\n } | points.js:20:1:33:1 | class C ... ;\\n }\\n} |
| privateFields.js:1:11:1:10 | constructor() {} | privateFields.js:1:11:1:10 | constructor | privateFields.js:1:11:1:10 | () {} | privateFields.js:1:1:22:1 | class F ... = 6;\\n} |
| privateFields.js:4:2:8:2 | reads() ... #if;\\n\\t} | privateFields.js:4:2:4:6 | reads | privateFields.js:4:7:8:2 | () {\\n\\t\\t ... #if;\\n\\t} | privateFields.js:1:1:22:1 | class F ... = 6;\\n} |
| privateFields.js:10:2:12:2 | equals( ... ecl;\\n\\t} | privateFields.js:10:2:10:7 | equals | privateFields.js:10:8:12:2 | (o) {\\n\\t ... ecl;\\n\\t} | privateFields.js:1:1:22:1 | class F ... = 6;\\n} |
| privateFields.js:14:2:17:2 | writes( ... = 5;\\n\\t} | privateFields.js:14:2:14:7 | writes | privateFields.js:14:8:17:2 | () {\\n\\t\\t ... = 5;\\n\\t} | privateFields.js:1:1:22:1 | class F ... = 6;\\n} |
| staticConstructor.js:1:15:1:14 | constructor() {} | staticConstructor.js:1:15:1:14 | constructor | staticConstructor.js:1:15:1:14 | () {} | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} |
| staticConstructor.js:2:3:2:59 | static ... tor"; } | staticConstructor.js:2:10:2:20 | constructor | staticConstructor.js:2:21:2:59 | () { re ... tor"; } | staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} |
| tst.js:2:3:2:50 | "constr ... r. */ } | tst.js:2:3:2:15 | "constructor" | tst.js:2:16:2:50 | () { /* ... r. */ } | tst.js:1:9:4:1 | class { ... */ }\\n} |
@@ -53,6 +73,10 @@ test_MethodDefinitions
| tst.js:12:3:12:8 | m() {} | tst.js:12:3:12:3 | m | tst.js:12:4:12:8 | () {} | tst.js:11:1:14:1 | class C ... () {}\\n} |
| tst.js:13:3:13:10 | [m]() {} | tst.js:13:4:13:4 | m | tst.js:13:6:13:10 | () {} | tst.js:11:1:14:1 | class C ... () {}\\n} |
test_getAMember
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | dataflow.js:4:12:4:11 | constructor() {} |
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | dataflow.js:5:3:5:17 | #priv = source; |
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | dataflow.js:6:3:8:3 | getPriv ... iv;\\n\\t\\t} |
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | dataflow.js:10:3:12:3 | getFals ... . \\n\\t\\t} |
| fields.js:1:1:4:1 | class C ... = 42\\n} | fields.js:1:9:1:8 | constructor() {} |
| fields.js:1:1:4:1 | class C ... = 42\\n} | fields.js:2:3:2:4 | x; |
| fields.js:1:1:4:1 | class C ... = 42\\n} | fields.js:3:3:3:8 | y = 42 |
@@ -63,6 +87,14 @@ test_getAMember
| points.js:20:1:33:1 | class C ... ;\\n }\\n} | points.js:21:3:24:3 | constru ... c;\\n } |
| points.js:20:1:33:1 | class C ... ;\\n }\\n} | points.js:26:3:28:3 | toStrin ... ur;\\n } |
| points.js:20:1:33:1 | class C ... ;\\n }\\n} | points.js:30:3:32:3 | static ... t";\\n } |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:1:11:1:10 | constructor() {} |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:2:2:2:15 | #privDecl = 3; |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:3:2:3:12 | #if = "if"; |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:4:2:8:2 | reads() ... #if;\\n\\t} |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:10:2:12:2 | equals( ... ecl;\\n\\t} |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:14:2:17:2 | writes( ... = 5;\\n\\t} |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:19:2:19:13 | #privSecond; |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:21:2:21:22 | ["#publ ... "] = 6; |
| staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | staticConstructor.js:1:15:1:14 | constructor() {} |
| staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | staticConstructor.js:2:3:2:59 | static ... tor"; } |
| tst.js:1:9:4:1 | class { ... */ }\\n} | tst.js:2:3:2:50 | "constr ... r. */ } |
@@ -72,6 +104,9 @@ test_getAMember
| tst.js:11:1:14:1 | class C ... () {}\\n} | tst.js:12:3:12:8 | m() {} |
| tst.js:11:1:14:1 | class C ... () {}\\n} | tst.js:13:3:13:10 | [m]() {} |
test_MethodNames
| dataflow.js:4:12:4:11 | constructor() {} | constructor |
| dataflow.js:6:3:8:3 | getPriv ... iv;\\n\\t\\t} | getPriv |
| dataflow.js:10:3:12:3 | getFals ... . \\n\\t\\t} | getFalsePrivate |
| fields.js:1:9:1:8 | constructor() {} | constructor |
| points.js:2:3:5:3 | constru ... y;\\n } | constructor |
| points.js:7:3:9:3 | get dis ... y);\\n } | dist |
@@ -80,6 +115,10 @@ test_MethodNames
| points.js:21:3:24:3 | constru ... c;\\n } | constructor |
| points.js:26:3:28:3 | toStrin ... ur;\\n } | toString |
| points.js:30:3:32:3 | static ... t";\\n } | className |
| privateFields.js:1:11:1:10 | constructor() {} | constructor |
| privateFields.js:4:2:8:2 | reads() ... #if;\\n\\t} | reads |
| privateFields.js:10:2:12:2 | equals( ... ecl;\\n\\t} | equals |
| privateFields.js:14:2:17:2 | writes( ... = 5;\\n\\t} | writes |
| staticConstructor.js:1:15:1:14 | constructor() {} | constructor |
| staticConstructor.js:2:3:2:59 | static ... tor"; } | constructor |
| tst.js:2:3:2:50 | "constr ... r. */ } | constructor |
@@ -94,27 +133,96 @@ test_SuperExpr
| points.js:27:12:27:16 | super |
| tst.js:7:19:7:23 | super |
test_SyntheticConstructors
| dataflow.js:4:12:4:11 | constructor() {} |
| fields.js:1:9:1:8 | constructor() {} |
| privateFields.js:1:11:1:10 | constructor() {} |
| staticConstructor.js:1:15:1:14 | constructor() {} |
| tst.js:11:9:11:8 | constructor() {} |
test_ConstructorDefinitions
| dataflow.js:4:12:4:11 | constructor() {} |
| fields.js:1:9:1:8 | constructor() {} |
| points.js:2:3:5:3 | constru ... y;\\n } |
| points.js:21:3:24:3 | constru ... c;\\n } |
| privateFields.js:1:11:1:10 | constructor() {} |
| staticConstructor.js:1:15:1:14 | constructor() {} |
| tst.js:2:3:2:50 | "constr ... r. */ } |
| tst.js:7:3:7:38 | constru ... get); } |
| tst.js:11:9:11:8 | constructor() {} |
test_ClassNodeConstructor
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | dataflow.js:4:12:4:11 | () {} |
| fields.js:1:1:4:1 | class C ... = 42\\n} | fields.js:1:9:1:8 | () {} |
| points.js:1:1:18:1 | class P ... ;\\n }\\n} | points.js:2:14:5:3 | (x, y) ... y;\\n } |
| points.js:20:1:33:1 | class C ... ;\\n }\\n} | points.js:21:14:24:3 | (x, y, ... c;\\n } |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | privateFields.js:1:11:1:10 | () {} |
| staticConstructor.js:1:1:3:1 | class M ... r"; }\\n} | staticConstructor.js:1:15:1:14 | () {} |
| tst.js:1:9:4:1 | class { ... */ }\\n} | tst.js:2:16:2:50 | () { /* ... r. */ } |
| tst.js:6:1:8:1 | class B ... t); }\\n} | tst.js:7:14:7:38 | () { su ... get); } |
| tst.js:11:1:14:1 | class C ... () {}\\n} | tst.js:11:9:11:8 | () {} |
test_ClassNodeInstanceMethod
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | getFalsePrivate | dataflow.js:10:18:12:3 | () {\\n\\t\\t ... . \\n\\t\\t} |
| dataflow.js:4:2:13:2 | class F ... \\n\\t\\t}\\n\\t} | getPriv | dataflow.js:6:10:8:3 | () {\\n\\t\\t ... iv;\\n\\t\\t} |
| points.js:1:1:18:1 | class P ... ;\\n }\\n} | toString | points.js:11:11:13:3 | () {\\n ... )";\\n } |
| points.js:20:1:33:1 | class C ... ;\\n }\\n} | toString | points.js:26:11:28:3 | () {\\n ... ur;\\n } |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | equals | privateFields.js:10:8:12:2 | (o) {\\n\\t ... ecl;\\n\\t} |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | reads | privateFields.js:4:7:8:2 | () {\\n\\t\\t ... #if;\\n\\t} |
| privateFields.js:1:1:22:1 | class F ... = 6;\\n} | writes | privateFields.js:14:8:17:2 | () {\\n\\t\\t ... = 5;\\n\\t} |
| tst.js:1:9:4:1 | class { ... */ }\\n} | constructor | tst.js:3:18:3:56 | () { /* ... r. */ } |
| tst.js:11:1:14:1 | class C ... () {}\\n} | m | tst.js:12:4:12:8 | () {} |
getAccessModifier
| dataflow.js:4:12:4:11 | constructor() {} | dataflow.js:4:12:4:11 | constructor | Public |
| dataflow.js:5:3:5:17 | #priv = source; | dataflow.js:5:3:5:7 | #priv | Private |
| dataflow.js:6:3:8:3 | getPriv ... iv;\\n\\t\\t} | dataflow.js:6:3:6:9 | getPriv | Public |
| dataflow.js:7:11:7:20 | this.#priv | dataflow.js:7:16:7:20 | #priv | Private |
| dataflow.js:10:3:12:3 | getFals ... . \\n\\t\\t} | dataflow.js:10:3:10:17 | getFalsePrivate | Public |
| dataflow.js:11:11:11:23 | this["#priv"] | dataflow.js:11:16:11:22 | "#priv" | Public |
| dataflow.js:14:7:14:23 | new Foo().getPriv | dataflow.js:14:17:14:23 | getPriv | Public |
| dataflow.js:16:7:16:31 | new Foo ... Private | dataflow.js:16:17:16:31 | getFalsePrivate | Public |
| fields.js:1:9:1:8 | constructor() {} | fields.js:1:9:1:8 | constructor | Public |
| fields.js:3:3:3:8 | y = 42 | fields.js:3:3:3:3 | y | Public |
| points.js:2:3:5:3 | constru ... y;\\n } | points.js:2:3:2:13 | constructor | Public |
| points.js:3:5:3:10 | this.x | points.js:3:10:3:10 | x | Public |
| points.js:4:5:4:10 | this.y | points.js:4:10:4:10 | y | Public |
| points.js:7:3:9:3 | get dis ... y);\\n } | points.js:7:7:7:10 | dist | Public |
| points.js:8:12:8:20 | Math.sqrt | points.js:8:17:8:20 | sqrt | Public |
| points.js:8:22:8:27 | this.x | points.js:8:27:8:27 | x | Public |
| points.js:8:29:8:34 | this.x | points.js:8:34:8:34 | x | Public |
| points.js:8:36:8:41 | this.y | points.js:8:41:8:41 | y | Public |
| points.js:8:43:8:48 | this.y | points.js:8:48:8:48 | y | Public |
| points.js:11:3:13:3 | toStrin ... )";\\n } | points.js:11:3:11:10 | toString | Public |
| points.js:12:18:12:23 | this.x | points.js:12:23:12:23 | x | Public |
| points.js:12:34:12:39 | this.y | points.js:12:39:12:39 | y | Public |
| points.js:15:3:17:3 | static ... t";\\n } | points.js:15:10:15:18 | className | Public |
| points.js:21:3:24:3 | constru ... c;\\n } | points.js:21:3:21:13 | constructor | Public |
| points.js:23:5:23:15 | this.colour | points.js:23:10:23:15 | colour | Public |
| points.js:26:3:28:3 | toStrin ... ur;\\n } | points.js:26:3:26:10 | toString | Public |
| points.js:27:12:27:25 | super.toString | points.js:27:18:27:25 | toString | Public |
| points.js:27:40:27:50 | this.colour | points.js:27:45:27:50 | colour | Public |
| points.js:30:3:32:3 | static ... t";\\n } | points.js:30:10:30:18 | className | Public |
| privateFields.js:1:11:1:10 | constructor() {} | privateFields.js:1:11:1:10 | constructor | Public |
| privateFields.js:2:2:2:15 | #privDecl = 3; | privateFields.js:2:2:2:10 | #privDecl | Private |
| privateFields.js:3:2:3:12 | #if = "if"; | privateFields.js:3:2:3:4 | #if | Private |
| privateFields.js:4:2:8:2 | reads() ... #if;\\n\\t} | privateFields.js:4:2:4:6 | reads | Public |
| privateFields.js:5:13:5:25 | this.#privUse | privateFields.js:5:18:5:25 | #privUse | Private |
| privateFields.js:6:13:6:35 | this["# ... puted"] | privateFields.js:6:18:6:34 | "#publicComputed" | Public |
| privateFields.js:7:13:7:20 | this.#if | privateFields.js:7:18:7:20 | #if | Private |
| privateFields.js:10:2:12:2 | equals( ... ecl;\\n\\t} | privateFields.js:10:2:10:7 | equals | Public |
| privateFields.js:11:10:11:23 | this.#privDecl | privateFields.js:11:15:11:23 | #privDecl | Private |
| privateFields.js:11:29:11:39 | o.#privDecl | privateFields.js:11:31:11:39 | #privDecl | Private |
| privateFields.js:14:2:17:2 | writes( ... = 5;\\n\\t} | privateFields.js:14:2:14:7 | writes | Public |
| privateFields.js:15:3:15:16 | this.#privDecl | privateFields.js:15:8:15:16 | #privDecl | Private |
| privateFields.js:16:3:16:17 | this["#public"] | privateFields.js:16:8:16:16 | "#public" | Public |
| privateFields.js:21:2:21:22 | ["#publ ... "] = 6; | privateFields.js:21:3:21:16 | "#publicField" | Public |
| staticConstructor.js:1:15:1:14 | constructor() {} | staticConstructor.js:1:15:1:14 | constructor | Public |
| staticConstructor.js:2:3:2:59 | static ... tor"; } | staticConstructor.js:2:10:2:20 | constructor | Public |
| staticConstructor.js:4:1:4:11 | console.log | staticConstructor.js:4:9:4:11 | log | Public |
| staticConstructor.js:4:13:4:31 | MyClass.constructor | staticConstructor.js:4:21:4:31 | constructor | Public |
| tst.js:2:3:2:50 | "constr ... r. */ } | tst.js:2:3:2:15 | "constructor" | Public |
| tst.js:3:3:3:56 | ["const ... r. */ } | tst.js:3:4:3:16 | "constructor" | Public |
| tst.js:7:3:7:38 | constru ... get); } | tst.js:7:3:7:13 | constructor | Public |
| tst.js:11:9:11:8 | constructor() {} | tst.js:11:9:11:8 | constructor | Public |
| tst.js:12:3:12:8 | m() {} | tst.js:12:3:12:3 | m | Public |
| tst.js:13:3:13:10 | [m]() {} | tst.js:13:4:13:4 | m | Public |
| tst.js:17:3:17:20 | m() { return 42; } | tst.js:17:3:17:3 | m | Public |
dataflow
| dataflow.js:2:15:2:22 | "source" | dataflow.js:14:7:14:25 | new Foo().getPriv() |
| dataflow.js:2:15:2:22 | "source" | dataflow.js:16:7:16:33 | new Foo ... ivate() |

View File

@@ -16,3 +16,5 @@ import SyntheticConstructors
import ConstructorDefinitions
import ClassNodeConstructor
import ClassNodeInstanceMethod
import PrivateField
import ClassFlow