@@ -304,8 +304,12 @@ module EssaFlow {
304
304
// see `with_flow` in `python/ql/src/semmle/python/dataflow/Implementation.qll`
305
305
with .getContextExpr ( ) = contextManager .getNode ( ) and
306
306
with .getOptionalVars ( ) = var .getNode ( ) and
307
- not with .isAsync ( ) and
308
307
contextManager .strictlyDominates ( var )
308
+ // note: we allow this for both `with` and `async with`, since some
309
+ // implementations do `async def __aenter__(self): return self`, so you can do
310
+ // both:
311
+ // * `foo = x.foo(); await foo.async_methoid(); foo.close()` and
312
+ // * `async with x.foo() as foo: await foo.async_method()`.
309
313
)
310
314
or
311
315
// Async with var definition
@@ -314,6 +318,12 @@ module EssaFlow {
314
318
// nodeTo is `x`, essa var
315
319
//
316
320
// This makes the cfg node the local source of the awaited value.
321
+ //
322
+ // We have this step in addition to the step above, to handle cases where the QL
323
+ // modeling of `f(42)` requires a `.getAwaited()` step (in API graphs) when not
324
+ // using `async with`, so you can do both:
325
+ // * `foo = await x.foo(); await foo.async_methoid(); foo.close()` and
326
+ // * `async with x.foo() as foo: await foo.async_method()`.
317
327
exists ( With with , ControlFlowNode var |
318
328
nodeFrom .( CfgNode ) .getNode ( ) = var and
319
329
nodeTo .( EssaNode ) .getVar ( ) .getDefinition ( ) .( WithDefinition ) .getDefiningNode ( ) = var and
0 commit comments