forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPrintAst.qll
More file actions
836 lines (704 loc) · 25.4 KB
/
Copy pathPrintAst.qll
File metadata and controls
836 lines (704 loc) · 25.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
/**
* Provides queries to pretty-print a JavaScript AST as a graph.
*
* By default, this will print the AST for all elements in the database. To change this behavior,
* extend `PrintAstConfiguration` and override `shouldPrint` to hold for only the elements
* you wish to view the AST for.
*/
import javascript
private newtype TPrintAstConfiguration = MkPrintAstConfiguration()
/**
* The query can extend this class to control which elements are printed.
*/
class PrintAstConfiguration extends TPrintAstConfiguration {
/**
* Gets a textual representation of this `PrintAstConfiguration`.
*/
string toString() { result = "PrintAstConfiguration" }
/**
* Controls whether the `Element` should be considered for AST printing.
* By default it checks whether the `Element` `e` belongs to `Location` `l`.
*/
predicate shouldPrint(Locatable e, Location l) { l = e.getLocation() }
}
private predicate shouldPrint(Locatable e, Location l) {
exists(PrintAstConfiguration config | config.shouldPrint(e, l))
}
/** Holds if the given element does not need to be rendered in the AST, due to being the `TopLevel` for a file. */
private predicate isNotNeeded(Locatable el) {
el instanceof TopLevel and
el.getLocation().getStartLine() = 0 and
el.getLocation().getStartColumn() = 0
or
// relaxing aggresive type inference.
none()
}
/**
* Retrieves the canonical QL class(es) for entity `el`
*/
private string getQlClass(Locatable el) {
result = "[" + el.getPrimaryQlClasses() + "] "
// Alternative implementation -- do not delete. It is useful for QL class discovery.
// not el.getAPrimaryQlClass() = "???" and result = "[" + getPrimaryQlClasses() + "] " or el.getAPrimaryQlClass() = "???" and result = "??[" + concat(el.getAQlClass(), ",") + "] "
}
/**
* Printed nodes for different file types.
*/
private newtype TPrintAstNode =
// JavaScript / TypeScript
TElementNode(ASTNode el) { shouldPrint(el, _) and not isNotNeeded(el) } or
TParametersNode(Function f) { shouldPrint(f, _) and not isNotNeeded(f) } or
TTypeParametersNode(TypeParameterized f) { shouldPrint(f, _) and not isNotNeeded(f) } or
TJSXAttributesNode(JSXElement n) { shouldPrint(n, _) and not isNotNeeded(n) } or
TJSXBodyElementsNode(JSXNode n) { shouldPrint(n, _) and not isNotNeeded(n) } or
TInvokeArgumentsNode(InvokeExpr n) { shouldPrint(n, _) and not isNotNeeded(n) } or
TInvokeTypeArgumentsNode(InvokeExpr invk) { shouldPrint(invk, _) and not isNotNeeded(invk) } or
// JSON
TJSONNode(JSONValue value) { shouldPrint(value, _) and not isNotNeeded(value) } or
// YAML
TYAMLNode(YAMLNode n) { shouldPrint(n, _) and not isNotNeeded(n) } or
TYAMLMappingNode(YAMLMapping mapping, int i) {
shouldPrint(mapping, _) and not isNotNeeded(mapping) and exists(mapping.getKeyNode(i))
} or
// HTML
THTMLElementNode(HTML::Element e) { shouldPrint(e, _) and not isNotNeeded(e) } or
THTMLAttributesNodes(HTML::Element e) { shouldPrint(e, _) and not isNotNeeded(e) } or
THTMLAttributeNode(HTML::Attribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) } or
THTMLScript(Script script) { shouldPrint(script, _) and not isNotNeeded(script) } or
THTMLCodeInAttr(CodeInAttribute attr) { shouldPrint(attr, _) and not isNotNeeded(attr) } or
TRegExpTermNode(RegExpTerm term) {
shouldPrint(term, _) and
term.isUsedAsRegExp() and
any(RegExpLiteral lit).getRoot() = term.getRootTerm()
}
/**
* A node in the output tree.
*/
class PrintAstNode extends TPrintAstNode {
/**
* Gets a textual representation of this node in the PrintAst output tree.
*/
string toString() { none() }
/**
* Gets the child node at index `childIndex`. Child indices must be unique,
* but need not be contiguous.
*/
PrintAstNode getChild(int childIndex) { none() }
/**
* Gets a child of this node.
*/
final PrintAstNode getAChild() { result = this.getChild(_) }
/**
* Gets the parent of this node, if any.
*/
final PrintAstNode getParent() { result.getAChild() = this }
/**
* Gets the location of this node in the source code.
*/
Location getLocation() { none() }
/**
* Gets the value of the property of this node, where the name of the property
* is `key`.
*/
string getProperty(string key) {
key = "semmle.label" and
result = this.toString()
}
/**
* Gets the label for the edge from this node to the specified child. By
* default, this is just the index of the child, but subclasses can override
* this.
*/
string getChildEdgeLabel(int childIndex) {
exists(this.getChild(childIndex)) and
result = childIndex.toString()
}
}
/** A top-level AST node. */
class TopLevelPrintAstNode extends PrintAstNode {
TopLevelPrintAstNode() { not exists(this.getParent()) }
private int getOrder() {
this =
rank[result](TopLevelPrintAstNode n, Location l |
l = n.getLocation()
|
n
order by
l.getFile().getRelativePath(), l.getStartLine(), l.getStartColumn(), l.getEndLine(),
l.getEndColumn()
)
}
override string getProperty(string key) {
result = super.getProperty(key)
or
key = "semmle.order" and
result = this.getOrder().toString()
}
}
/**
* Classes for printing JavaScript AST.
*/
private module PrintJavaScript {
/**
* A print node representing an `ASTNode`.
*
* Provides a default implemention that works for some (but not all) ASTNode's.
* More specific subclasses can override this class to get more specific behavior.
*
* The more specific subclasses are mostly used aggregate the children of the `ASTNode`.
* For example by aggregating all the parameters of a function under a single child node.
*/
class ElementNode extends PrintAstNode, TElementNode {
ASTNode element;
ElementNode() {
this = TElementNode(element) and
not element instanceof Script and // Handled in module `PrintHTML`
not element instanceof CodeInAttribute // Handled in module `PrintHTML`
}
override string toString() { result = getQlClass(element) + PrettyPrinting::print(element) }
override Location getLocation() { result = element.getLocation() }
/**
* Gets the `ASTNode` represented by this node.
*/
final ASTNode getElement() { result = element }
override PrintAstNode getChild(int childIndex) {
exists(ASTNode el | result.(ElementNode).getElement() = el |
el = this.getChildNode(childIndex)
)
}
/**
* Gets the `i`th child of `element`.
* Can be overriden in subclasses to get more specific behavior for `getChild()`.
*/
ASTNode getChildNode(int childIndex) { result = getLocationSortedChild(element, childIndex) }
}
/** Provides predicates for pretty printing `ASTNode`s. */
private module PrettyPrinting {
/**
* Gets a pretty string representation of `element`.
* Either the result is `ASTNode::toString`, or a custom made string representation of `element`.
*/
string print(ASTNode element) {
shouldPrint(element, _) and
(
result = element.toString().regexpReplaceAll("(\\\\n|\\\\r|\\\\t| )+", " ") and
not exists(repr(element))
or
result = repr(element)
)
}
/**
* Gets a string representing `a`.
*/
private string repr(ASTNode a) {
shouldPrint(a, _) and
(
exists(DeclStmt decl | decl = a |
result =
getDeclarationKeyword(decl) + " " +
strictconcat(string name, int i |
name = decl.getDecl(i).getBindingPattern().getName()
|
name, ", " order by i
) + " = ..."
)
or
exists(ObjectExpr obj | obj = a | result = "{" + obj.getProperty(0).getName() + ": ...}")
or
result = a.(Property).getName() + ": " + repr(a.(Property).getInit())
or
result = a.(Literal).getRawValue()
or
result = a.(Identifier).getName()
)
}
/**
* Gets "var" or "const" or "let" depending on what type of declaration `decl` is.
*/
private string getDeclarationKeyword(DeclStmt decl) {
decl instanceof VarDeclStmt and result = "var"
or
decl instanceof ConstDeclStmt and result = "const"
or
decl instanceof LetStmt and result = "let"
}
}
private ASTNode getLocationSortedChild(ASTNode parent, int i) {
result =
rank[i](ASTNode child, int childIndex |
child = parent.getChild(childIndex)
|
child
order by
child.getLocation().getStartLine(), child.getLocation().getStartColumn(), childIndex
)
}
/**
* A print node for function invocations.
*
* The children of this node are split into 3.
* 1: The callee.
* 2: An aggregate node for all the arguments.
* 3: An aggregate node for all the type argument.
*/
class InvokeNode extends ElementNode {
override InvokeExpr element;
override PrintAstNode getChild(int childIndex) {
childIndex = 0 and result.(ElementNode).getElement() = element.getCallee()
or
childIndex = 1 and
exists(element.getAnArgument()) and
result.(InvokeArgumentsNode).getInvokeExpr() = element
or
childIndex = 2 and
exists(element.getATypeArgument()) and
result.(InvokeTypeArgumentsNode).getInvokeExpr() = element
}
}
/**
* A print node for regexp literals.
*
* The single child of this node is the root `RegExpTerm`.
*/
class RegexpNode extends ElementNode {
override RegExpLiteral element;
override PrintAstNode getChild(int childIndex) {
childIndex = 0 and
result.(RegExpTermNode).getTerm() = element.getRoot()
}
}
/**
* A print node for regexp terms.
*/
class RegExpTermNode extends PrintAstNode, TRegExpTermNode {
RegExpTerm term;
RegExpTermNode() { this = TRegExpTermNode(term) }
RegExpTerm getTerm() { result = term }
override PrintAstNode getChild(int childIndex) {
result.(RegExpTermNode).getTerm() = term.getChild(childIndex)
}
override string toString() { result = getQlClass(term) + term.toString() }
override Location getLocation() { result = term.getLocation() }
}
/**
* An aggregate node representing all the arguments for an function invocation.
*/
class InvokeArgumentsNode extends PrintAstNode, TInvokeArgumentsNode {
InvokeExpr invk;
InvokeArgumentsNode() { this = TInvokeArgumentsNode(invk) and exists(invk.getAnArgument()) }
override string toString() { result = "(Arguments)" }
/**
* Gets the `InvokeExpr` for which this node represents the arguments.
*/
InvokeExpr getInvokeExpr() { result = invk }
override PrintAstNode getChild(int childIndex) {
result.(ElementNode).getElement() = invk.getArgument(childIndex)
}
}
/**
* An aggregate node representing all the type-arguments for an function invocation.
*/
class InvokeTypeArgumentsNode extends PrintAstNode, TInvokeTypeArgumentsNode {
InvokeExpr invk;
InvokeTypeArgumentsNode() {
this = TInvokeTypeArgumentsNode(invk) and exists(invk.getATypeArgument())
}
override string toString() { result = "(TypeArguments)" }
/**
* Gets the `InvokeExpr` for which this node represents the type-arguments.
*/
InvokeExpr getInvokeExpr() { result = invk }
override PrintAstNode getChild(int childIndex) {
result.(ElementNode).getElement() = invk.getTypeArgument(childIndex)
}
}
/**
* A print node for JSX nodes.
*
* The children of this node are split into 3.
* 1: The name of the JSX node (for example `Name` in `<Name href={foo} />`).
* 2: An aggregate node for all the attributes (for example `href={foo}` in `<Name href={foo} />`).
* 3: An aggregate node for all the body element (for example `foo` in `<span>foo</span>`).
*/
class JSXNodeNode extends ElementNode {
override JSXNode element;
override PrintAstNode getChild(int childIndex) {
childIndex = 0 and result.(ElementNode).getElement() = element.(JSXElement).getNameExpr()
or
childIndex = 1 and
exists(element.getABodyElement()) and
result.(JSXBodyElementsNode).getJSXNode() = element
or
childIndex = 2 and
exists(element.(JSXElement).getAttribute(_)) and
result.(JSXAttributesNode).getJSXElement() = element
}
}
/**
* An aggregate node representing all the attributes in a `JSXNode`.
*/
class JSXAttributesNode extends PrintAstNode, TJSXAttributesNode {
JSXElement n;
JSXAttributesNode() { this = TJSXAttributesNode(n) and exists(n.getAttribute(_)) }
override string toString() { result = "(Attributes)" }
/**
* Gets the `JSXElement` for which this node represents the attributes.
*/
JSXElement getJSXElement() { result = n }
override PrintAstNode getChild(int childIndex) {
result.(ElementNode).getElement() = n.getAttribute(childIndex)
}
}
/**
* An aggregate node representing all the body elements in a `JSXNode`.
*/
class JSXBodyElementsNode extends PrintAstNode, TJSXBodyElementsNode {
JSXNode n;
JSXBodyElementsNode() { this = TJSXBodyElementsNode(n) and exists(n.getBodyElement(_)) }
override string toString() { result = "(Body)" }
/**
* Gets the `JSXNode` for which this node represents the body elements.
*/
JSXNode getJSXNode() { result = n }
override PrintAstNode getChild(int childIndex) {
result.(ElementNode).getElement() = n.getBodyElement(childIndex)
}
}
/**
* A node representing any `ASTNode` that has type-parameters.
*
* The first child of this node is an aggregate node representing all the type-parameters.
*/
class TypeParameterizedNode extends ElementNode {
override TypeParameterized element;
override PrintAstNode getChild(int childIndex) {
childIndex = -100 and result.(TypeParametersNode).getTypeParameterized() = element
or
result = super.getChild(childIndex) and
not result.(ElementNode).getElement() = element.getATypeParameter()
}
}
/**
* A `PrintAstNode` for functions.
*
* The children of this node is split into 6:
* - The identifier (name) of the function.
* - An aggregate node for all the parameters of the function.
* - An aggregate node for all the type parameters of the function.
* - The `this` type annotation.
* - The return type annotation.
* - The body
*/
class FunctionNode extends TypeParameterizedNode {
override Function element;
override PrintAstNode getChild(int childIndex) {
childIndex = 0 and result.(ElementNode).getElement() = element.getIdentifier()
or
childIndex = 1 and
result.(ParametersNode).getFunction() = element and
exists(element.getAParameter())
or
childIndex = 2 and
result.(TypeParametersNode).getTypeParameterized() = element and
exists(element.getATypeParameter())
or
childIndex = 3 and result.(ElementNode).getElement() = element.getThisTypeAnnotation()
or
childIndex = 4 and result.(ElementNode).getElement() = element.getReturnTypeAnnotation()
or
childIndex = 5 and result.(ElementNode).getElement() = element.getBody()
}
}
/**
* A `PrintAstNode` for parameters.
*
* This node puts the type-annotation and default value of a parameter as children of the parameter itself.
* Instead of the default behavior (from `ElementNode`) where they would be children of the function.
*/
class ParameterNode extends ElementNode {
override Parameter element;
override ASTNode getChildNode(int childIndex) {
childIndex = 0 and result = element.getTypeAnnotation()
or
childIndex = 1 and result = element.getDefault()
}
}
/**
* An aggregate node representing all the parameters in a function.
*/
class ParametersNode extends PrintAstNode, TParametersNode {
Function f;
ParametersNode() { this = TParametersNode(f) and exists(f.getAParameter()) }
override string toString() { result = "(Parameters)" }
/**
* Gets the `Function` for which this node represents the parameters.
*/
Function getFunction() { result = f }
override PrintAstNode getChild(int childIndex) {
result.(ElementNode).getElement() = f.getParameter(childIndex)
}
}
/**
* An aggregate node representing all the type parameters in a function.
*/
class TypeParametersNode extends PrintAstNode, TTypeParametersNode {
TypeParameterized f;
TypeParametersNode() { this = TTypeParametersNode(f) and exists(f.getATypeParameter()) }
override string toString() { result = "(TypeParameters)" }
/**
* Gets the `Function` for which this node represents the type-parameters.
*/
TypeParameterized getTypeParameterized() { result = f }
override PrintAstNode getChild(int childIndex) {
result.(ElementNode).getElement() = f.getTypeParameter(childIndex)
}
}
}
/**
* Classes for printing JSON AST.
*/
private module PrintJSON {
/**
* A print node representing a JSON value in a .json file.
*/
class JSONNode extends PrintAstNode, TJSONNode {
JSONValue value;
JSONNode() { this = TJSONNode(value) }
override string toString() { result = getQlClass(value) + PrettyPrinting::print(value) }
override Location getLocation() { result = value.getLocation() }
/**
* Gets the `JSONValue` represented by this node.
*/
final JSONValue getValue() { result = value }
override PrintAstNode getChild(int childIndex) {
exists(JSONValue child | result.(JSONNode).getValue() = child |
child = value.getChild(childIndex)
)
}
}
/** Provied predicates for pretty printing JSON. */
private module PrettyPrinting {
/**
* Gets a string representation of `n`.
* Either using the default `JSONValue::toString`, or a custom printing of the JSON value.
*/
string print(JSONValue n) {
shouldPrint(n, _) and
(
result = n.toString().regexpReplaceAll("(\\\\n|\\\\r|\\\\t| )+", " ") and
not exists(repr(n))
or
result = repr(n)
)
}
/** Gets a string representing `n`. */
private string repr(JSONValue n) {
shouldPrint(n, _) and
(
exists(JSONObject obj, string name, JSONValue prop | obj = n |
prop = obj.getPropValue(name) and
prop = obj.getChild(0) and
result = "{" + name + ": ...}"
)
or
n instanceof JSONObject and not exists(n.getChild(_)) and result = "{}"
or
result = n.(JSONPrimitiveValue).getRawValue()
or
exists(JSONArray arr | arr = n |
result = "[]" and not exists(arr.getChild(_))
or
result = "[" + repr(arr.getChild(0)) + "]" and not exists(arr.getChild(1))
or
result = "[" + repr(arr.getChild(0)) + ", ...]" and exists(arr.getChild(1))
)
)
}
}
}
/**
* Classes for printing YAML AST.
*/
module PrintYAML {
/**
* A print node representing a YAML value in a .yml file.
*/
class YAMLNodeNode extends PrintAstNode, TYAMLNode {
YAMLNode node;
YAMLNodeNode() { this = TYAMLNode(node) }
override string toString() { result = getQlClass(node) + node.toString() }
override Location getLocation() { result = node.getLocation() }
/**
* Gets the `YAMLNode` represented by this node.
*/
final YAMLNode getValue() { result = node }
override PrintAstNode getChild(int childIndex) {
exists(YAMLNode child | result.(YAMLNodeNode).getValue() = child |
child = node.getChildNode(childIndex)
)
}
}
/**
* A print node representing a `YAMLMapping`.
*
* Each child of this node aggregates the key and value of a mapping.
*/
class YAMLMappingNode extends YAMLNodeNode {
override YAMLMapping node;
override PrintAstNode getChild(int childIndex) {
exists(YAMLMappingMapNode map | map = result | map.maps(node, childIndex))
}
}
/**
* A print node representing the `i`th mapping in `mapping`.
*/
class YAMLMappingMapNode extends PrintAstNode, TYAMLMappingNode {
YAMLMapping mapping;
int i;
YAMLMappingMapNode() { this = TYAMLMappingNode(mapping, i) }
override string toString() {
result = "(Mapping " + i + ")" and not exists(mapping.getKeyNode(i).(YAMLScalar).getValue())
or
result = "(Mapping " + i + ") " + mapping.getKeyNode(i).(YAMLScalar).getValue() + ":"
}
/**
* Holds if this print node represents the `index`th mapping of `m`.
*/
predicate maps(YAMLMapping m, int index) {
m = mapping and
index = i
}
override PrintAstNode getChild(int childIndex) {
childIndex = 0 and result.(YAMLNodeNode).getValue() = mapping.getKeyNode(i)
or
childIndex = 1 and result.(YAMLNodeNode).getValue() = mapping.getValueNode(i)
}
}
}
/**
* Classes for printing HTML AST.
*/
module PrintHTML {
/**
* A print node representing an HTML node in a .html file.
*/
class HTMLElementNode extends PrintAstNode, THTMLElementNode {
HTML::Element element;
HTMLElementNode() { this = THTMLElementNode(element) }
override string toString() { result = getQlClass(element) + "<" + element.getName() + " ..." }
override Location getLocation() { result = element.getLocation() }
/**
* Gets the `HTML::Element` represented by this node.
*/
final HTML::Element getElement() { result = element }
override PrintAstNode getChild(int childIndex) {
childIndex = -1 and result.(HTMLAttributesNodes).getElement() = element
or
exists(HTML::Element child | result.(HTMLElementNode).getElement() = child |
child = element.getChild(childIndex)
)
}
}
/**
* A print node representing an HTML node in a .html file.
*/
class HTMLScriptElementNode extends HTMLElementNode {
override HTML::ScriptElement element;
override PrintAstNode getChild(int childIndex) {
childIndex = -200 and result.(HTMLScript).getScript() = element.getScript()
or
result = super.getChild(childIndex)
}
}
/**
* A print node representing the code inside a `<script>` element.
*/
class HTMLScript extends PrintAstNode, THTMLScript {
Script script;
HTMLScript() {
this = THTMLScript(script) and
any(HTMLScriptElementNode se).getElement().(HTML::ScriptElement).getScript() = script
}
override string toString() { result = "(Script)" }
override Location getLocation() { result = script.getLocation() }
/**
* Gets the `Script` for which this node represents code.
*/
Script getScript() { result = script }
override PrintAstNode getChild(int childIndex) {
result.(PrintJavaScript::ElementNode).getElement() = script.getChild(childIndex)
}
}
/**
* A print node representing the code inside an attribute.
*/
class HTMLCodeInAttr extends PrintAstNode, THTMLCodeInAttr {
CodeInAttribute attr;
HTMLCodeInAttr() {
this = THTMLCodeInAttr(attr) and
any(HTMLAttributeNode an).getAttribute().getCodeInAttribute() = attr
}
override string toString() { result = "(Script)" }
override Location getLocation() { result = attr.getLocation() }
/**
* Gets the `CodeInAttribute` for which this node represents code.
*/
CodeInAttribute getCode() { result = attr }
override PrintAstNode getChild(int childIndex) {
result.(PrintJavaScript::ElementNode).getElement() = attr.getChild(childIndex)
}
}
/**
* An aggregate node representing all the attributes of an HTMLElement.
*/
class HTMLAttributesNodes extends PrintAstNode, THTMLAttributesNodes {
HTML::Element element;
HTMLAttributesNodes() {
this = THTMLAttributesNodes(element) and exists(element.getAttribute(_))
}
override string toString() { result = "(Attributes)" }
/**
* Gets the `HTMLElement` for which this node represents the attributes.
*/
HTML::Element getElement() { result = element }
override PrintAstNode getChild(int childIndex) {
result.(HTMLAttributeNode).getAttribute() = element.getAttribute(childIndex)
}
}
/**
* A print node representing an HTML attribute in a .html file.
*/
class HTMLAttributeNode extends PrintAstNode, THTMLAttributeNode {
HTML::Attribute attr;
HTMLAttributeNode() { this = THTMLAttributeNode(attr) }
override string toString() { result = getQlClass(attr) + attr.toString() }
override Location getLocation() { result = attr.getLocation() }
/**
* Gets the `HTMLAttribute` represented by this node.
*/
final HTML::Attribute getAttribute() { result = attr }
override PrintAstNode getChild(int childIndex) {
childIndex = 0 and result.(HTMLCodeInAttr).getCode() = attr.getCodeInAttribute()
}
}
}
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
query predicate nodes(PrintAstNode node, string key, string value) { value = node.getProperty(key) }
/**
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
* given `value`.
*/
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
exists(int childIndex |
target = source.getChild(childIndex) and
(
key = "semmle.label" and value = source.getChildEdgeLabel(childIndex)
or
key = "semmle.order" and value = childIndex.toString()
)
)
}
/** Holds if property `key` of the graph has the given `value`. */
query predicate graphProperties(string key, string value) {
key = "semmle.graphKind" and value = "tree"
}