diff --git a/python/.vscode/ql.code-snippets b/python/.vscode/ql.code-snippets index 4ded97b8439..cebd4c1533a 100644 --- a/python/.vscode/ql.code-snippets +++ b/python/.vscode/ql.code-snippets @@ -195,11 +195,42 @@ "", " /** Gets a reference to an instance of `${TM_SELECTED_TEXT}`. */", " DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }", + "", + " /**", + " * Taint propagation for `${TM_SELECTED_TEXT}`.", + " */", + " private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {", + " override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {", + " // Methods", + " //", + " // TODO: When we have tools that make it easy, model these properly to handle", + " // `meth = obj.meth; meth()`. Until then, we'll use this more syntactic approach", + " // (since it allows us to at least capture the most common cases).", + " nodeFrom = instance() and", + " exists(DataFlow::AttrRead attr | attr.getObject() = nodeFrom |", + " // normal (non-async) methods", + " attr.getAttributeName() in [\"TODO\"] and", + " nodeTo.(DataFlow::CallCfgNode).getFunction() = attr", + " or", + " // async methods", + " exists(Await await, DataFlow::CallCfgNode call |", + " attr.getAttributeName() in [\"TODO\"] and", + " call.getFunction() = attr and", + " await.getValue() = call.asExpr() and", + " nodeTo.asExpr() = await", + " )", + " )", + " or", + " // Attributes", + " nodeFrom = instance() and", + " nodeTo.(DataFlow::AttrRead).getObject() = nodeFrom and", + " nodeTo.(DataFlow::AttrRead).getAttributeName() in [\"TODO\"]", + " }", + " }", "}", ], "description": "Type tracking class (select full class path before inserting)", }, - "API graph .getMember chain": { "scope": "ql", "prefix": "api graph .getMember chain",