-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathprintAst.qll
More file actions
214 lines (181 loc) · 6.51 KB
/
printAst.qll
File metadata and controls
214 lines (181 loc) · 6.51 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
/**
* Provides queries to pretty-print a Ruby abstract syntax tree as a graph.
*
* By default, this will print the AST for all nodes in the database. To change
* this behavior, extend `PrintASTConfiguration` and override `shouldPrintNode`
* to hold for only the AST nodes you wish to view.
*/
private import AST
private import codeql.ruby.Regexp as RE
private import codeql.ruby.ast.internal.Synthesis
private import ast.internal.AST
/**
* The query can extend this class to control which nodes are printed.
*/
class PrintAstConfiguration extends string {
PrintAstConfiguration() { this = "PrintAstConfiguration" }
/**
* Holds if the given node should be printed.
*/
predicate shouldPrintNode(AstNode n) { not isDesugarNode(n) }
predicate shouldPrintAstEdge(AstNode parent, string edgeName, AstNode child) {
child = parent.getAChild(edgeName) and
not child = parent.getDesugared()
}
}
private predicate shouldPrintNode(AstNode n) {
any(PrintAstConfiguration config).shouldPrintNode(n)
}
private predicate shouldPrintAstEdge(AstNode parent, string edgeName, AstNode child) {
any(PrintAstConfiguration config).shouldPrintAstEdge(parent, edgeName, child)
}
newtype TPrintNode =
TPrintRegularAstNode(AstNode n) { shouldPrintNode(n) } or
TPrintRegExpNode(RE::RegExpTerm term) {
exists(RegExpLiteral literal |
shouldPrintNode(literal) and
term.getRootTerm() = literal.getParsed()
)
}
/**
* A node in the output tree.
*/
class PrintAstNode extends TPrintNode {
/** Gets a textual representation of this node in the PrintAst output tree. */
string toString() { none() }
/**
* Gets the child node with name `edgeName`. Typically this is the name of the
* predicate used to access the child.
*/
PrintAstNode getChild(string edgeName) { 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 }
/**
* Holds if this node is at the specified location. The location spans column
* `startcolumn` of line `startline` to column `endcolumn` of line `endline`
* in file `filepath`. For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
none()
}
/** Gets a value used to order this node amongst its siblings. */
int getOrder() { none() }
/**
* Gets the value of the property of this node, where the name of the property
* is `key`.
*/
final string getProperty(string key) {
key = "semmle.label" and
result = this.toString()
or
key = "semmle.order" and result = this.getOrder().toString()
}
}
/** An `AstNode` in the output tree. */
class PrintRegularAstNode extends PrintAstNode, TPrintRegularAstNode {
AstNode astNode;
PrintRegularAstNode() { this = TPrintRegularAstNode(astNode) }
override string toString() {
result = "[" + concat(astNode.getAPrimaryQlClass(), ", ") + "] " + astNode.toString()
}
override PrintAstNode getChild(string edgeName) {
exists(AstNode child | shouldPrintAstEdge(astNode, edgeName, child) |
result = TPrintRegularAstNode(child)
)
or
// If this AST node is a regexp literal, add the parsed regexp tree as a
// child.
exists(RE::RegExpTerm t | t = astNode.(RegExpLiteral).getParsed() |
result = TPrintRegExpNode(t) and edgeName = "getParsed"
)
}
private predicate parentIsSynthesized() {
exists(AstNode parent |
shouldPrintAstEdge(parent, _, astNode) and
parent.isSynthesized()
)
}
private int getSynthAstNodeIndex() {
exists(AstNode parent |
shouldPrintAstEdge(parent, _, astNode) and
synthChild(parent, result, astNode)
)
or
not exists(AstNode parent |
shouldPrintAstEdge(parent, _, astNode) and
synthChild(parent, _, astNode)
) and
result = 0
}
private int getSynthAstNodeIndexForSynthParent() {
if this.parentIsSynthesized() then result = this.getSynthAstNodeIndex() else result = 0
}
override int getOrder() {
this =
rank[result](PrintRegularAstNode p, Location l, File f |
l = p.getLocation() and
f = l.getFile()
|
p
order by
f.getBaseName(), f.getAbsolutePath(), l.getStartLine(),
p.getSynthAstNodeIndexForSynthParent(), l.getStartColumn(), p.getSynthAstNodeIndex(),
l.getEndLine(), l.getEndColumn()
)
}
/** Gets the location of this node. */
Location getLocation() { result = astNode.getLocation() }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
astNode.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
/** A parsed regexp node in the output tree. */
class PrintRegExpNode extends PrintAstNode, TPrintRegExpNode {
RE::RegExpTerm regexNode;
PrintRegExpNode() { this = TPrintRegExpNode(regexNode) }
override string toString() {
result = "[" + concat(regexNode.getAPrimaryQlClass(), ", ") + "] " + regexNode.toString()
}
override PrintAstNode getChild(string edgeName) {
// Use the child index as an edge name.
exists(int i | result = TPrintRegExpNode(regexNode.getChild(i)) and edgeName = i.toString())
}
override int getOrder() { exists(RE::RegExpTerm p | p.getChild(result) = regexNode) }
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
regexNode.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
/**
* 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) {
target = source.getChild(_) and
(
key = "semmle.label" and
value = strictconcat(string name | source.getChild(name) = target | name, "/")
or
key = "semmle.order" and
value = target.getProperty("semmle.order")
)
}
/**
* Holds if property `key` of the graph has the given `value`.
*/
query predicate graphProperties(string key, string value) {
key = "semmle.graphKind" and value = "tree"
}