Skip to content

Commit 5200af5

Browse files
committed
Python: Add code snippets for VS Code
Notice that in this form, the filename doesn't matter, and you need to specify `scope` to limit the snippet to only trigger for `ql`.
1 parent 6696d18 commit 5200af5

File tree

1 file changed

+355
-0
lines changed

1 file changed

+355
-0
lines changed

python/.vscode/ql.code-snippets

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
{
2+
// Place your python workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
3+
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
4+
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
5+
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
6+
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
7+
// Placeholders with the same ids are connected.
8+
// Example:
9+
// "Print to console": {
10+
// "scope": "javascript,typescript",
11+
// "prefix": "log",
12+
// "body": [
13+
// "console.log('$1');",
14+
// "$2"
15+
// ],
16+
// "description": "Log output to console"
17+
// }
18+
19+
"Has relative path": {
20+
"scope": "ql",
21+
"prefix": "has relative path",
22+
"body": [
23+
"exists($1.getLocation().getFile().getRelativePath())"
24+
],
25+
"description": "has relative path",
26+
},
27+
28+
"Exists": {
29+
"scope": "ql",
30+
"prefix": "exists",
31+
"body": [
32+
"exists(${1:DataFlow::Node node} |",
33+
" $2",
34+
")"
35+
],
36+
"description": "Exists clause",
37+
},
38+
39+
"Predicate": {
40+
"scope": "ql",
41+
"prefix": "predicate",
42+
"body": [
43+
"predicate ${1:isFoo}(${2:DataFlow::Node node}) {",
44+
" ${3:any()}",
45+
"}"
46+
],
47+
"description": "Predicate",
48+
},
49+
50+
"Class": {
51+
"scope": "ql",
52+
"prefix": "class",
53+
"body": [
54+
"class ${1:MyClass} extends ${2:DataFlow::MethodCallNode} {",
55+
" $1() { ${3:getMethodName() = \"foo\"} }",
56+
"",
57+
" DataFlow::Node ${4:getThing}() { result = ${5:getArgument(0)} }",
58+
"}"
59+
],
60+
"description": "Class",
61+
},
62+
63+
"Abstract class": {
64+
"scope": "ql",
65+
"prefix": "abstract class",
66+
"body": [
67+
"abstract class ${1:AdditionalThing} extends ${2:DataFlow::Node} {",
68+
" abstract ${3:DataFlow::Node} ${4:getThing}($5);",
69+
"}"
70+
],
71+
"description": "Class",
72+
},
73+
74+
"Class::Range": {
75+
"scope": "ql",
76+
"prefix": "range class",
77+
"body": [
78+
"class ${1:MyClass} extends ${2:DataFlow::Node} {",
79+
" $1::Range range;",
80+
"",
81+
" $1() { this = range }",
82+
"",
83+
" ${3:DataFlow::Node} ${4:getThing}() { result = range.$4() }",
84+
"}",
85+
"",
86+
"module $1 {",
87+
" abstract class Range extends $2 {",
88+
" abstract $3 $4();",
89+
" }",
90+
"}",
91+
],
92+
"description": "Class with ::Range pattern",
93+
},
94+
95+
"Class::Range delegate": {
96+
"scope": "ql",
97+
"prefix": "range delegate",
98+
"body": [
99+
"${1:DataFlow::Node} ${2:getThing}() { result = range.$2() }"
100+
],
101+
"description": "Predicate that delegates to range class",
102+
},
103+
104+
"Type tracking predicate": {
105+
"scope": "ql",
106+
"prefix": "type tracking",
107+
"body": [
108+
"/** Gets a reference to a ${3:thing}. */",
109+
"private DataFlow::Node ${1:myType}(DataFlow::TypeTracker t) {",
110+
" t.start() and",
111+
" result = ${2:value}",
112+
" or",
113+
" exists(DataFlow::TypeTracker t2 |",
114+
" result = $1(t2).track(t2, t)",
115+
" )",
116+
"}",
117+
"",
118+
"/** Gets a reference to a ${3:thing}. */",
119+
"DataFlow::Node $1() {",
120+
" result = $1(DataFlow::TypeTracker::end())",
121+
"}"
122+
],
123+
"description": "Type tracking predicate",
124+
},
125+
126+
"Type tracking module": {
127+
"scope": "ql",
128+
"prefix": "type tracking module",
129+
"body": [
130+
"// ---------------------------------------------------------------------------",
131+
"// ${1:modulename}",
132+
"// ---------------------------------------------------------------------------",
133+
"/** Gets a reference to the `$1` module. */",
134+
"private DataFlow::Node $1(DataFlow::TypeTracker t) {",
135+
" t.start() and",
136+
" result = DataFlow::importNode(\"$1\")",
137+
" or",
138+
" exists(DataFlow::TypeTracker t2 | result = $1(t2).track(t2, t))",
139+
"}",
140+
"",
141+
"/** Gets a reference to the `$1` module. */",
142+
"DataFlow::Node $1() { result = $1(DataFlow::TypeTracker::end()) }",
143+
"",
144+
"/**",
145+
" * Gets a reference to the attribute `attr_name` of the `$1` module.",
146+
" * WARNING: Only holds for a few predefined attributes.",
147+
" */",
148+
"private DataFlow::Node $1_attr(DataFlow::TypeTracker t, string attr_name) {",
149+
" attr_name in [\"${2:name}\"] and",
150+
" (",
151+
" t.start() and",
152+
" result = DataFlow::importNode(\"$1\" + \".\" + attr_name)",
153+
" or",
154+
" t.startInAttr(attr_name) and",
155+
" result = $1()",
156+
" )",
157+
" or",
158+
" // Due to bad performance when using normal setup with `$1_attr(t2, attr_name).track(t2, t)`",
159+
" // we have inlined that code and forced a join",
160+
" exists(DataFlow::TypeTracker t2 |",
161+
" exists(DataFlow::StepSummary summary |",
162+
" $1_attr_first_join(t2, attr_name, result, summary) and",
163+
" t = t2.append(summary)",
164+
" )",
165+
" )",
166+
"}",
167+
"",
168+
"pragma[nomagic]",
169+
"private predicate $1_attr_first_join(",
170+
" DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary",
171+
") {",
172+
" DataFlow::StepSummary::step($1_attr(t2, attr_name), res, summary)",
173+
"}",
174+
"",
175+
"/**",
176+
" * Gets a reference to the attribute `attr_name` of the `$1` module.",
177+
" * WARNING: Only holds for a few predefined attributes.",
178+
" */",
179+
"private DataFlow::Node $1_attr(string attr_name) {",
180+
" result = $1_attr(DataFlow::TypeTracker::end(), attr_name)",
181+
"}",
182+
"",
183+
"/** Provides models for the `$1` module. */",
184+
"module $1 {",
185+
"",
186+
"}",
187+
],
188+
"description": "Type tracking module",
189+
},
190+
191+
"Type tracking module member": {
192+
"scope": "ql",
193+
"prefix": "type tracking module member",
194+
"body": [
195+
"/** Gets a reference to the `${1:module}.${2:member}` ${3:object/class}. */",
196+
"private DataFlow::Node ${4:$2}(DataFlow::TypeTracker t) {",
197+
" t.start() and",
198+
" result = DataFlow::importNode(\"$1.$2\")",
199+
" or",
200+
" t.startInAttr(\"$2\") and",
201+
" result = $1()",
202+
" or",
203+
" exists(DataFlow::TypeTracker t2 | result = $4(t2).track(t2, t))",
204+
"}",
205+
" ",
206+
"/** Gets a reference to the `$1.$2` $3. */",
207+
"DataFlow::Node $4() { result = $4(DataFlow::TypeTracker::end()) }",
208+
],
209+
"description": "Type tracking module member",
210+
},
211+
212+
"Taint tracking configuration": {
213+
"scope": "ql",
214+
"prefix": "taint tracking",
215+
"body": [
216+
"/** @kind path-problem */",
217+
"import python",
218+
"import experimental.dataflow.DataFlow",
219+
"import experimental.dataflow.TaintTracking",
220+
"import experimental.semmle.python.Concepts",
221+
"import experimental.dataflow.RemoteFlowSources",
222+
"import DataFlow::PathGraph",
223+
"class ${1:Config} extends TaintTracking::Configuration {",
224+
" $1() { this = \"$1\" } ",
225+
"",
226+
" override predicate isSource(DataFlow::Node node) {",
227+
" ${2:none()}",
228+
" }",
229+
"",
230+
" override predicate isSink(DataFlow::Node node) {",
231+
" ${3:none()}",
232+
" }",
233+
"}",
234+
"",
235+
"from $1 cfg, DataFlow::PathNode source, DataFlow::PathNode sink",
236+
"where cfg.hasFlowPath(source, sink)",
237+
"select sink, source, sink, \"taint from $@\", source.getNode(), \"here\""
238+
]
239+
},
240+
241+
"Type tracking submodule": {
242+
"scope": "ql",
243+
"prefix": "type tracking submodule",
244+
"body": [
245+
" // -------------------------------------------------------------------------",
246+
" // ${1:parent}.${2:submodule}",
247+
" // -------------------------------------------------------------------------",
248+
" /** Gets a reference to the `$1.$2` module. */",
249+
" DataFlow::Node $2() { result = $1_attr(\"$2\") }",
250+
"",
251+
" /** Provides models for the `$1.$2` module */",
252+
" module $2 {",
253+
" /**",
254+
" * Gets a reference to the attribute `attr_name` of the `$1.$2` module.",
255+
" * WARNING: Only holds for a few predefined attributes.",
256+
" */",
257+
" private DataFlow::Node $2_attr(DataFlow::TypeTracker t, string attr_name) {",
258+
" attr_name in [\"$3\"] and",
259+
" (",
260+
" t.start() and",
261+
" result = DataFlow::importNode(\"$1.$2\" + \".\" + attr_name)",
262+
" or",
263+
" t.startInAttr(attr_name) and",
264+
" result = $2()",
265+
" )",
266+
" or",
267+
" // Due to bad performance when using normal setup with `$2_attr(t2, attr_name).track(t2, t)`",
268+
" // we have inlined that code and forced a join",
269+
" exists(DataFlow::TypeTracker t2 |",
270+
" exists(DataFlow::StepSummary summary |",
271+
" $2_attr_first_join(t2, attr_name, result, summary) and",
272+
" t = t2.append(summary)",
273+
" )",
274+
" )",
275+
" }",
276+
"",
277+
" pragma[nomagic]",
278+
" private predicate $2_attr_first_join(",
279+
" DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,",
280+
" DataFlow::StepSummary summary",
281+
" ) {",
282+
" DataFlow::StepSummary::step($2_attr(t2, attr_name), res, summary)",
283+
" }",
284+
"",
285+
" /**",
286+
" * Gets a reference to the attribute `attr_name` of the `$1.$2` module.",
287+
" * WARNING: Only holds for a few predefined attributes.",
288+
" */",
289+
" private DataFlow::Node $2_attr(string attr_name) {",
290+
" result = $2_attr(DataFlow::TypeTracker::end(), attr_name)",
291+
" }",
292+
" }",
293+
],
294+
"description": "Type tracking submodule",
295+
},
296+
297+
"Type tracking class": {
298+
"scope": "ql",
299+
"prefix": "type tracking class",
300+
"body": [
301+
" /**",
302+
" * Provides models for the `${1:module}.${2:classname}` class",
303+
" *",
304+
" * See ${6:apiref}.",
305+
" */",
306+
" module $2 {",
307+
" /** Gets a reference to the `$1.$2` class. */",
308+
" private DataFlow::Node classRef(DataFlow::TypeTracker t) {",
309+
" t.start() and",
310+
" result = ${4:module}_attr(\"$2\")",
311+
" or",
312+
" // TODO: remove/expand this part of the template as needed",
313+
" // Handle `${5:toplevel}.$2` alias",
314+
" t.start() and",
315+
" result = $5_attr(\"$2\")",
316+
" or",
317+
" exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t))",
318+
" }",
319+
"",
320+
" /** Gets a reference to the `$1.$2` class. */",
321+
" DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) }",
322+
"",
323+
" /**",
324+
" * A source of an instance of `$1.$2`.",
325+
" *",
326+
" * This can include instantiation of the class, return value from function",
327+
" * calls, or a special parameter that will be set when functions are call by external",
328+
" * library.",
329+
" *",
330+
" * Use `$2::instance()` predicate to get references to instances of `$1.$2`.",
331+
" */",
332+
" abstract class InstanceSource extends DataFlow::Node { }",
333+
"",
334+
" /** A direct instantiation of `$1.$2`. */",
335+
" private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {",
336+
" override CallNode node;",
337+
"",
338+
" ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }",
339+
" }",
340+
"",
341+
" /** Gets a reference to an instance of `$1.$2`. */",
342+
" private DataFlow::Node instance(DataFlow::TypeTracker t) {",
343+
" t.start() and",
344+
" result instanceof InstanceSource",
345+
" or",
346+
" exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))",
347+
" }",
348+
"",
349+
" /** Gets a reference to an instance of `$1.$2`. */",
350+
" DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }",
351+
" }",
352+
],
353+
"description": "Type tracking class",
354+
},
355+
}

0 commit comments

Comments
 (0)