diff --git a/python/.vscode/ql.code-snippets b/python/.vscode/ql.code-snippets new file mode 100644 index 00000000000..17b8e37dad3 --- /dev/null +++ b/python/.vscode/ql.code-snippets @@ -0,0 +1,355 @@ +{ + // Place your python workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + // "Print to console": { + // "scope": "javascript,typescript", + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } + + "Has relative path": { + "scope": "ql", + "prefix": "has relative path", + "body": [ + "exists($1.getLocation().getFile().getRelativePath())" + ], + "description": "has relative path", + }, + + "Exists": { + "scope": "ql", + "prefix": "exists", + "body": [ + "exists(${1:DataFlow::Node node} |", + " $2", + ")" + ], + "description": "Exists clause", + }, + + "Predicate": { + "scope": "ql", + "prefix": "predicate", + "body": [ + "predicate ${1:isFoo}(${2:DataFlow::Node node}) {", + " ${3:any()}", + "}" + ], + "description": "Predicate", + }, + + "Class": { + "scope": "ql", + "prefix": "class", + "body": [ + "class ${1:MyClass} extends ${2:DataFlow::MethodCallNode} {", + " $1() { ${3:getMethodName() = \"foo\"} }", + "", + " DataFlow::Node ${4:getThing}() { result = ${5:getArgument(0)} }", + "}" + ], + "description": "Class", + }, + + "Abstract class": { + "scope": "ql", + "prefix": "abstract class", + "body": [ + "abstract class ${1:AdditionalThing} extends ${2:DataFlow::Node} {", + " abstract ${3:DataFlow::Node} ${4:getThing}($5);", + "}" + ], + "description": "Class", + }, + + "Class::Range": { + "scope": "ql", + "prefix": "range class", + "body": [ + "class ${1:MyClass} extends ${2:DataFlow::Node} {", + " $1::Range range;", + "", + " $1() { this = range }", + "", + " ${3:DataFlow::Node} ${4:getThing}() { result = range.$4() }", + "}", + "", + "module $1 {", + " abstract class Range extends $2 {", + " abstract $3 $4();", + " }", + "}", + ], + "description": "Class with ::Range pattern", + }, + + "Class::Range delegate": { + "scope": "ql", + "prefix": "range delegate", + "body": [ + "${1:DataFlow::Node} ${2:getThing}() { result = range.$2() }" + ], + "description": "Predicate that delegates to range class", + }, + + "Type tracking predicate": { + "scope": "ql", + "prefix": "type tracking", + "body": [ + "/** Gets a reference to a ${3:thing}. */", + "private DataFlow::Node ${1:myType}(DataFlow::TypeTracker t) {", + " t.start() and", + " result = ${2:value}", + " or", + " exists(DataFlow::TypeTracker t2 |", + " result = $1(t2).track(t2, t)", + " )", + "}", + "", + "/** Gets a reference to a ${3:thing}. */", + "DataFlow::Node $1() {", + " result = $1(DataFlow::TypeTracker::end())", + "}" + ], + "description": "Type tracking predicate", + }, + + "Type tracking module": { + "scope": "ql", + "prefix": "type tracking module", + "body": [ + "// ---------------------------------------------------------------------------", + "// ${1:modulename}", + "// ---------------------------------------------------------------------------", + "/** Gets a reference to the `$1` module. */", + "private DataFlow::Node $1(DataFlow::TypeTracker t) {", + " t.start() and", + " result = DataFlow::importNode(\"$1\")", + " or", + " exists(DataFlow::TypeTracker t2 | result = $1(t2).track(t2, t))", + "}", + "", + "/** Gets a reference to the `$1` module. */", + "DataFlow::Node $1() { result = $1(DataFlow::TypeTracker::end()) }", + "", + "/**", + " * Gets a reference to the attribute `attr_name` of the `$1` module.", + " * WARNING: Only holds for a few predefined attributes.", + " */", + "private DataFlow::Node $1_attr(DataFlow::TypeTracker t, string attr_name) {", + " attr_name in [\"${2:name}\"] and", + " (", + " t.start() and", + " result = DataFlow::importNode(\"$1\" + \".\" + attr_name)", + " or", + " t.startInAttr(attr_name) and", + " result = $1()", + " )", + " or", + " // Due to bad performance when using normal setup with `$1_attr(t2, attr_name).track(t2, t)`", + " // we have inlined that code and forced a join", + " exists(DataFlow::TypeTracker t2 |", + " exists(DataFlow::StepSummary summary |", + " $1_attr_first_join(t2, attr_name, result, summary) and", + " t = t2.append(summary)", + " )", + " )", + "}", + "", + "pragma[nomagic]", + "private predicate $1_attr_first_join(", + " DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary", + ") {", + " DataFlow::StepSummary::step($1_attr(t2, attr_name), res, summary)", + "}", + "", + "/**", + " * Gets a reference to the attribute `attr_name` of the `$1` module.", + " * WARNING: Only holds for a few predefined attributes.", + " */", + "private DataFlow::Node $1_attr(string attr_name) {", + " result = $1_attr(DataFlow::TypeTracker::end(), attr_name)", + "}", + "", + "/** Provides models for the `$1` module. */", + "module $1 {", + "", + "}", + ], + "description": "Type tracking module", + }, + + "Type tracking module member": { + "scope": "ql", + "prefix": "type tracking module member", + "body": [ + "/** Gets a reference to the `${1:module}.${2:member}` ${3:object/class}. */", + "private DataFlow::Node ${4:$2}(DataFlow::TypeTracker t) {", + " t.start() and", + " result = DataFlow::importNode(\"$1.$2\")", + " or", + " t.startInAttr(\"$2\") and", + " result = $1()", + " or", + " exists(DataFlow::TypeTracker t2 | result = $4(t2).track(t2, t))", + "}", + " ", + "/** Gets a reference to the `$1.$2` $3. */", + "DataFlow::Node $4() { result = $4(DataFlow::TypeTracker::end()) }", + ], + "description": "Type tracking module member", + }, + + "Taint tracking configuration": { + "scope": "ql", + "prefix": "taint tracking", + "body": [ + "/** @kind path-problem */", + "import python", + "import experimental.dataflow.DataFlow", + "import experimental.dataflow.TaintTracking", + "import experimental.semmle.python.Concepts", + "import experimental.dataflow.RemoteFlowSources", + "import DataFlow::PathGraph", + "class ${1:Config} extends TaintTracking::Configuration {", + " $1() { this = \"$1\" } ", + "", + " override predicate isSource(DataFlow::Node node) {", + " ${2:none()}", + " }", + "", + " override predicate isSink(DataFlow::Node node) {", + " ${3:none()}", + " }", + "}", + "", + "from $1 cfg, DataFlow::PathNode source, DataFlow::PathNode sink", + "where cfg.hasFlowPath(source, sink)", + "select sink, source, sink, \"taint from $@\", source.getNode(), \"here\"" + ] + }, + + "Type tracking submodule": { + "scope": "ql", + "prefix": "type tracking submodule", + "body": [ + " // -------------------------------------------------------------------------", + " // ${1:parent}.${2:submodule}", + " // -------------------------------------------------------------------------", + " /** Gets a reference to the `$1.$2` module. */", + " DataFlow::Node $2() { result = $1_attr(\"$2\") }", + "", + " /** Provides models for the `$1.$2` module */", + " module $2 {", + " /**", + " * Gets a reference to the attribute `attr_name` of the `$1.$2` module.", + " * WARNING: Only holds for a few predefined attributes.", + " */", + " private DataFlow::Node $2_attr(DataFlow::TypeTracker t, string attr_name) {", + " attr_name in [\"$3\"] and", + " (", + " t.start() and", + " result = DataFlow::importNode(\"$1.$2\" + \".\" + attr_name)", + " or", + " t.startInAttr(attr_name) and", + " result = $2()", + " )", + " or", + " // Due to bad performance when using normal setup with `$2_attr(t2, attr_name).track(t2, t)`", + " // we have inlined that code and forced a join", + " exists(DataFlow::TypeTracker t2 |", + " exists(DataFlow::StepSummary summary |", + " $2_attr_first_join(t2, attr_name, result, summary) and", + " t = t2.append(summary)", + " )", + " )", + " }", + "", + " pragma[nomagic]", + " private predicate $2_attr_first_join(", + " DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,", + " DataFlow::StepSummary summary", + " ) {", + " DataFlow::StepSummary::step($2_attr(t2, attr_name), res, summary)", + " }", + "", + " /**", + " * Gets a reference to the attribute `attr_name` of the `$1.$2` module.", + " * WARNING: Only holds for a few predefined attributes.", + " */", + " private DataFlow::Node $2_attr(string attr_name) {", + " result = $2_attr(DataFlow::TypeTracker::end(), attr_name)", + " }", + " }", + ], + "description": "Type tracking submodule", + }, + + "Type tracking class": { + "scope": "ql", + "prefix": "type tracking class", + "body": [ + " /**", + " * Provides models for the `${1:module}.${2:classname}` class", + " *", + " * See ${6:apiref}.", + " */", + " module $2 {", + " /** Gets a reference to the `$1.$2` class. */", + " private DataFlow::Node classRef(DataFlow::TypeTracker t) {", + " t.start() and", + " result = ${4:module}_attr(\"$2\")", + " or", + " // TODO: remove/expand this part of the template as needed", + " // Handle `${5:toplevel}.$2` alias", + " t.start() and", + " result = $5_attr(\"$2\")", + " or", + " exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t))", + " }", + "", + " /** Gets a reference to the `$1.$2` class. */", + " DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) }", + "", + " /**", + " * A source of an instance of `$1.$2`.", + " *", + " * This can include instantiation of the class, return value from function", + " * calls, or a special parameter that will be set when functions are call by external", + " * library.", + " *", + " * Use `$2::instance()` predicate to get references to instances of `$1.$2`.", + " */", + " abstract class InstanceSource extends DataFlow::Node { }", + "", + " /** A direct instantiation of `$1.$2`. */", + " private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {", + " override CallNode node;", + "", + " ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }", + " }", + "", + " /** Gets a reference to an instance of `$1.$2`. */", + " private DataFlow::Node instance(DataFlow::TypeTracker t) {", + " t.start() and", + " result instanceof InstanceSource", + " or", + " exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))", + " }", + "", + " /** Gets a reference to an instance of `$1.$2`. */", + " DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }", + " }", + ], + "description": "Type tracking class", + }, +}