Skip to content

Commit c4e244e

Browse files
committed
Python: Add getAwaited to API::Node
I _really_ wanted to call this `.await()`, but that did not fit in with the convention, or the corresponding `getPromised` in JS. https://github.com/github/codeql/blob/54f191cfe37e136bcc7189b2fb01f44dbb01758b/javascript/ql/src/semmle/javascript/ApiGraphs.qll#L184
1 parent e29b756 commit c4e244e

File tree

3 files changed

+23
-5
lines changed

3 files changed

+23
-5
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* API graph nodes now contain a `getAwaited()` member predicate, for getting the result of awaiting an item, such as `await foo`.

python/ql/src/semmle/python/ApiGraphs.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ module API {
9797
*/
9898
Node getASubclass() { result = getASuccessor(Label::subclass()) }
9999

100+
/**
101+
* Gets a node representing the result from awaiting this node.
102+
*/
103+
Node getAwaited() { result = getASuccessor(Label::await()) }
104+
100105
/**
101106
* Gets a string representation of the lexicographically least among all shortest access paths
102107
* from the root to this node.
@@ -469,6 +474,14 @@ module API {
469474
exists(DataFlow::Node superclass | pred.flowsTo(superclass) |
470475
ref.asExpr().(ClassExpr).getABase() = superclass.asExpr()
471476
)
477+
or
478+
// awaiting
479+
exists(Await await, DataFlow::Node awaitedValue |
480+
lbl = Label::await() and
481+
ref.asExpr() = await and
482+
await.getValue() = awaitedValue.asExpr() and
483+
pred.flowsTo(awaitedValue)
484+
)
472485
)
473486
or
474487
// Built-ins, treated as members of the module `builtins`
@@ -587,4 +600,7 @@ private module Label {
587600

588601
/** Gets the `subclass` edge label. */
589602
string subclass() { result = "getASubclass()" }
603+
604+
/** Gets the `await` edge label. */
605+
string await() { result = "getAwaited()" }
590606
}

python/ql/test/experimental/dataflow/ApiGraphs/async_test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
async def foo():
44
coro = pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn()
55
coro # $ use=moduleImport("pkg").getMember("async_func").getReturn()
6-
result = await coro # $ use=moduleImport("pkg").getMember("async_func").getReturn()
7-
result # $ MISSING: use=...
8-
return result # $ MISSING: use=...
6+
result = await coro # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
7+
result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
8+
return result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
99

1010
async def bar():
11-
result = await pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn()
12-
return result # $ MISSING: use=...
11+
result = await pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
12+
return result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
1313

1414
def check_annotations():
1515
# Just to make sure how annotations should look like :)

0 commit comments

Comments
 (0)