JS: API graph support for accessors (and classes)

This commit is contained in:
Asger Feldthaus
2022-03-30 10:54:07 +02:00
committed by Asger F
parent 1e9fcfb338
commit 33dac5e95f
4 changed files with 91 additions and 1 deletions

View File

@@ -604,12 +604,36 @@ module API {
or or
lbl = Label::promisedError() and lbl = Label::promisedError() and
PromiseFlow::storeStep(rhs, pred, Promises::errorProp()) PromiseFlow::storeStep(rhs, pred, Promises::errorProp())
or
// The return-value of a getter G counts as a definition of property G
// (Ordinary methods and properties are handled as PropWrite nodes)
exists(string name | lbl = Label::member(name) |
rhs = pred.(DataFlow::ObjectLiteralNode).getPropertyGetter(name).getAReturn()
or
rhs =
pred.(DataFlow::ClassNode)
.getStaticMember(name, DataFlow::MemberKind::getter())
.getAReturn()
)
or
// If `new C()` escapes, generate edges to its instance members
exists(DataFlow::ClassNode cls, string name |
pred = cls.getAClassReference().getAnInstantiation() and
lbl = Label::member(name)
|
rhs = cls.getInstanceMethod(name)
or
rhs = cls.getInstanceMember(name, DataFlow::MemberKind::getter()).getAReturn()
)
) )
or or
exists(DataFlow::ClassNode cls, string name | exists(DataFlow::ClassNode cls, string name |
base = MkClassInstance(cls) and base = MkClassInstance(cls) and
lbl = Label::member(name) and lbl = Label::member(name)
|
rhs = cls.getInstanceMethod(name) rhs = cls.getInstanceMethod(name)
or
rhs = cls.getInstanceMember(name, DataFlow::MemberKind::getter()).getAReturn()
) )
or or
exists(DataFlow::FunctionNode f | exists(DataFlow::FunctionNode f |

View File

@@ -0,0 +1 @@
import ApiGraphs.VerifyAssertions

View File

@@ -0,0 +1,65 @@
const foo = require('foo');
foo({
myMethod(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
console.log(x);
}
});
foo({
get myMethod() {
return function(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
console.log(x)
}
}
});
class C {
static myMethod(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
console.log(x);
}
}
foo(C);
class D {
myMethod(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
console.log(x);
}
}
foo(new D());
class E {
get myMethod() {
return function(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
console.log(x);
}
}
}
foo(new E());
class F {
static get myMethod() {
return function(x) { /* use (parameter 0 (member myMethod (parameter 0 (member exports (module foo))))) */
console.log(x);
}
}
}
foo(F);
// Cases where the class is instantiated in `foo`:
class G {
myMethod2(x) { /* use (parameter 0 (member myMethod2 (instance (parameter 0 (member exports (module foo)))))) */
console.log(x);
}
}
foo(G);
class H {
get myMethod2() {
return function (x) { /* use (parameter 0 (member myMethod2 (instance (parameter 0 (member exports (module foo)))))) */
console.log(x);
}
}
}
foo(H);