mirror of
https://github.com/github/codeql.git
synced 2025-12-21 11:16:30 +01:00
Python: Add syntactic support for yield in contextlib.contextmanager
This commit is contained in:
4
python/ql/lib/change-notes/2023-10-17-contextmanager.md
Normal file
4
python/ql/lib/change-notes/2023-10-17-contextmanager.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added support for functions decorated with `contextlib.contextmanager`.
|
||||
@@ -240,6 +240,19 @@ predicate hasPropertyDecorator(Function func) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function `func` has a `contextlib.contextmanager`.
|
||||
*/
|
||||
predicate hasContextmanagerDecorator(Function func) {
|
||||
exists(ControlFlowNode contextmanager |
|
||||
contextmanager.(NameNode).getId() = "contextmanager" and contextmanager.(NameNode).isGlobal()
|
||||
or
|
||||
contextmanager.(AttrNode).getObject("contextmanager").(NameNode).getId() = "contextlib"
|
||||
|
|
||||
func.getADecorator() = contextmanager.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Callables
|
||||
// =============================================================================
|
||||
@@ -1604,6 +1617,16 @@ class ExtractedReturnNode extends ReturnNode, CfgNode {
|
||||
override ReturnKind getKind() { any() }
|
||||
}
|
||||
|
||||
/** A data flow node that represents a value returned by a callable. */
|
||||
class YieldNodeInContextManagerFunction extends ReturnNode, CfgNode {
|
||||
YieldNodeInContextManagerFunction() {
|
||||
hasContextmanagerDecorator(node.getScope()) and
|
||||
node = any(Yield yield).getValue().getAFlowNode()
|
||||
}
|
||||
|
||||
override ReturnKind getKind() { any() }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents the output of a call. */
|
||||
abstract class OutNode extends Node {
|
||||
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
|
||||
|
||||
@@ -223,8 +223,8 @@ def managed_resource():
|
||||
yield x # $ tracked
|
||||
|
||||
def test_context_manager():
|
||||
with managed_resource() as x: # $ MISSING: tracked
|
||||
print(x) # $ MISSING: tracked
|
||||
with managed_resource() as x: # $ tracked
|
||||
print(x) # $ tracked
|
||||
|
||||
@contextlib.contextmanager
|
||||
def managed_resource2():
|
||||
@@ -232,5 +232,5 @@ def managed_resource2():
|
||||
yield x # $ tracked
|
||||
|
||||
def test_context_manager2():
|
||||
with managed_resource2() as x: # $ MISSING: tracked
|
||||
print(x) # $ MISSING: tracked
|
||||
with managed_resource2() as x: # $ tracked
|
||||
print(x) # $ tracked
|
||||
|
||||
Reference in New Issue
Block a user