Skip to content

Commit ad036f8

Browse files
authored
Merge pull request #179 from github/hvitved/synth-framework-take2
AST synthesis framework (take 2)
2 parents ca046c9 + 25f226e commit ad036f8

34 files changed

Lines changed: 1503 additions & 240 deletions

ql/consistency-queries/AstConsistency.ql

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ query predicate missingParent(AstNode node, string cls) {
1515

1616
query predicate multipleParents(AstNode node, AstNode parent, string cls) {
1717
parent = node.getParent() and
18-
count(node.getParent()) > 1 and
19-
cls = getAPrimaryQlClass(parent)
18+
cls = getAPrimaryQlClass(parent) and
19+
exists(AstNode one, AstNode two |
20+
one = node.getParent() and
21+
two = node.getParent() and
22+
one != two
23+
|
24+
one.isSynthesized() and two.isSynthesized()
25+
or
26+
not one.isSynthesized() and not two.isSynthesized()
27+
)
2028
}

ql/src/codeql_ruby/AST.qll

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import ast.Statement
1414
import ast.Variable
1515
private import ast.internal.AST
1616
private import ast.internal.Scope
17+
private import ast.internal.Synthesis
1718

1819
/**
1920
* A node in the abstract syntax tree. This class is the base class for all Ruby
@@ -56,7 +57,11 @@ class AstNode extends TAstNode {
5657
final AstNode getAChild() { result = this.getAChild(_) }
5758

5859
/** Gets the parent of this `AstNode`, if this node is not a root node. */
59-
final AstNode getParent() { result.getAChild() = this }
60+
final AstNode getParent() {
61+
result.getAChild() = this
62+
or
63+
result.getAChild().getDesugared() = this
64+
}
6065

6166
/**
6267
* Gets a child of this node, which can also be retrieved using a predicate
@@ -75,5 +80,25 @@ class AstNode extends TAstNode {
7580
* foo(123)
7681
* ```
7782
*/
78-
predicate isSynthesized() { this instanceof TImplicitSelf }
83+
final predicate isSynthesized() { this = getSynthChild(_, _) }
84+
85+
/**
86+
* Gets the desugared version of this AST node, if any.
87+
*
88+
* For example, the desugared version of
89+
*
90+
* ```rb
91+
* x += y
92+
* ```
93+
*
94+
* is
95+
*
96+
* ```rb
97+
* x = x + y
98+
* ```
99+
*
100+
* when `x` is a variable. Whenever an AST node can be desugared,
101+
* then the desugared version is used in the control-flow graph.
102+
*/
103+
final AstNode getDesugared() { result = getSynthChild(this, -1) }
79104
}

ql/src/codeql_ruby/ast/Call.qll

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ private class IdentifierMethodCall extends MethodCall, TIdentifierMethodCall {
137137

138138
final override string getMethodName() { result = getMethodName(this, g.getValue()) }
139139

140-
final override Self getReceiver() { result = TImplicitSelf(g) }
140+
final override Self getReceiver() { result = TSelfSynth(this, 0) }
141141
}
142142

143143
private class ScopeResolutionMethodCall extends MethodCall, TScopeResolutionMethodCall {
@@ -162,12 +162,7 @@ private class RegularMethodCall extends MethodCall, TRegularMethodCall {
162162
not exists(g.getReceiver()) and
163163
toGenerated(result) = g.getMethod().(Generated::ScopeResolution).getScope()
164164
or
165-
// If there's no explicit receiver (or scope resolution that acts like a
166-
// receiver), then the receiver is implicitly `self`. N.B. `::Foo()` is
167-
// not valid Ruby.
168-
not exists(g.getReceiver()) and
169-
not exists(g.getMethod().(Generated::ScopeResolution).getScope()) and
170-
result = TImplicitSelf(g)
165+
result = TSelfSynth(this, 0)
171166
}
172167

173168
final override string getMethodName() {

ql/src/codeql_ruby/ast/Expr.qll

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ class StmtSequence extends Expr, TStmtSequence {
7979
override AstNode getAChild(string pred) { pred = "getStmt" and result = this.getStmt(_) }
8080
}
8181

82+
private class StmtSequenceSynth extends StmtSequence, TStmtSequenceSynth {
83+
final override Stmt getStmt(int n) { synthChild(this, n, result) }
84+
85+
final override string toString() { result = "..." }
86+
}
87+
8288
private class Then extends StmtSequence, TThen {
8389
private Generated::Then g;
8490

@@ -210,11 +216,11 @@ class ParenthesizedExpr extends StmtSequence, TParenthesizedExpr {
210216

211217
ParenthesizedExpr() { this = TParenthesizedExpr(g) }
212218

219+
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
220+
213221
final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" }
214222

215223
final override string toString() { result = "( ... )" }
216-
217-
final override Stmt getStmt(int n) { toGenerated(result) = g.getChild(n) }
218224
}
219225

220226
/**

ql/src/codeql_ruby/ast/Operation.qll

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,6 @@ class DefinedExpr extends UnaryOperation, TDefinedExpr {
101101

102102
/** A binary operation. */
103103
class BinaryOperation extends Operation, TBinaryOperation {
104-
private Generated::Binary g;
105-
106-
BinaryOperation() { g = toGenerated(this) }
107-
108-
final override string getOperator() { result = g.getOperator() }
109-
110104
final override Expr getAnOperand() {
111105
result = this.getLeftOperand() or result = this.getRightOperand()
112106
}
@@ -122,10 +116,28 @@ class BinaryOperation extends Operation, TBinaryOperation {
122116
}
123117

124118
/** Gets the left operand of this binary operation. */
125-
final Stmt getLeftOperand() { toGenerated(result) = g.getLeft() }
119+
Stmt getLeftOperand() { none() }
126120

127121
/** Gets the right operand of this binary operation. */
128-
final Stmt getRightOperand() { toGenerated(result) = g.getRight() }
122+
Stmt getRightOperand() { none() }
123+
}
124+
125+
private class BinaryOperationReal extends BinaryOperation {
126+
private Generated::Binary g;
127+
128+
BinaryOperationReal() { g = toGenerated(this) }
129+
130+
final override string getOperator() { result = g.getOperator() }
131+
132+
final override Stmt getLeftOperand() { toGenerated(result) = g.getLeft() }
133+
134+
final override Stmt getRightOperand() { toGenerated(result) = g.getRight() }
135+
}
136+
137+
abstract private class BinaryOperationSynth extends BinaryOperation {
138+
final override Stmt getLeftOperand() { synthChild(this, 0, result) }
139+
140+
final override Stmt getRightOperand() { synthChild(this, 1, result) }
129141
}
130142

131143
/**
@@ -143,6 +155,10 @@ class AddExpr extends BinaryArithmeticOperation, TAddExpr {
143155
final override string getAPrimaryQlClass() { result = "AddExpr" }
144156
}
145157

158+
private class AddExprSynth extends AddExpr, BinaryOperationSynth, TAddExprSynth {
159+
final override string getOperator() { result = "+" }
160+
}
161+
146162
/**
147163
* A subtract expression.
148164
* ```rb
@@ -153,6 +169,10 @@ class SubExpr extends BinaryArithmeticOperation, TSubExpr {
153169
final override string getAPrimaryQlClass() { result = "SubExpr" }
154170
}
155171

172+
private class SubExprSynth extends SubExpr, BinaryOperationSynth, TSubExprSynth {
173+
final override string getOperator() { result = "-" }
174+
}
175+
156176
/**
157177
* A multiply expression.
158178
* ```rb
@@ -163,6 +183,10 @@ class MulExpr extends BinaryArithmeticOperation, TMulExpr {
163183
final override string getAPrimaryQlClass() { result = "MulExpr" }
164184
}
165185

186+
private class MulExprSynth extends MulExpr, BinaryOperationSynth, TMulExprSynth {
187+
final override string getOperator() { result = "*" }
188+
}
189+
166190
/**
167191
* A divide expression.
168192
* ```rb
@@ -173,6 +197,10 @@ class DivExpr extends BinaryArithmeticOperation, TDivExpr {
173197
final override string getAPrimaryQlClass() { result = "DivExpr" }
174198
}
175199

200+
private class DivExprSynth extends DivExpr, BinaryOperationSynth, TDivExprSynth {
201+
final override string getOperator() { result = "/" }
202+
}
203+
176204
/**
177205
* A modulo expression.
178206
* ```rb
@@ -183,6 +211,10 @@ class ModuloExpr extends BinaryArithmeticOperation, TModuloExpr {
183211
final override string getAPrimaryQlClass() { result = "ModuloExpr" }
184212
}
185213

214+
private class ModuloExprSynth extends ModuloExpr, BinaryOperationSynth, TModuloExprSynth {
215+
final override string getOperator() { result = "%" }
216+
}
217+
186218
/**
187219
* An exponent expression.
188220
* ```rb
@@ -193,6 +225,10 @@ class ExponentExpr extends BinaryArithmeticOperation, TExponentExpr {
193225
final override string getAPrimaryQlClass() { result = "ExponentExpr" }
194226
}
195227

228+
private class ExponentExprSynth extends ExponentExpr, BinaryOperationSynth, TExponentExprSynth {
229+
final override string getOperator() { result = "**" }
230+
}
231+
196232
/**
197233
* A binary logical operation.
198234
*/
@@ -209,6 +245,10 @@ class LogicalAndExpr extends BinaryLogicalOperation, TLogicalAndExpr {
209245
final override string getAPrimaryQlClass() { result = "LogicalAndExpr" }
210246
}
211247

248+
private class LogicalAndExprSynth extends LogicalAndExpr, BinaryOperationSynth, TLogicalAndExprSynth {
249+
final override string getOperator() { result = "&&" }
250+
}
251+
212252
/**
213253
* A logical OR operation, using either `or` or `||`.
214254
* ```rb
@@ -220,6 +260,10 @@ class LogicalOrExpr extends BinaryLogicalOperation, TLogicalOrExpr {
220260
final override string getAPrimaryQlClass() { result = "LogicalOrExpr" }
221261
}
222262

263+
private class LogicalOrExprSynth extends LogicalOrExpr, BinaryOperationSynth, TLogicalOrExprSynth {
264+
final override string getOperator() { result = "||" }
265+
}
266+
223267
/**
224268
* A binary bitwise operation.
225269
*/
@@ -235,6 +279,10 @@ class LShiftExpr extends BinaryBitwiseOperation, TLShiftExpr {
235279
final override string getAPrimaryQlClass() { result = "LShiftExpr" }
236280
}
237281

282+
private class LShiftExprSynth extends LShiftExpr, BinaryOperationSynth, TLShiftExprSynth {
283+
final override string getOperator() { result = "<<" }
284+
}
285+
238286
/**
239287
* A right-shift operation.
240288
* ```rb
@@ -245,6 +293,10 @@ class RShiftExpr extends BinaryBitwiseOperation, TRShiftExpr {
245293
final override string getAPrimaryQlClass() { result = "RShiftExpr" }
246294
}
247295

296+
private class RShiftExprSynth extends RShiftExpr, BinaryOperationSynth, TRShiftExprSynth {
297+
final override string getOperator() { result = ">>" }
298+
}
299+
248300
/**
249301
* A bitwise AND operation.
250302
* ```rb
@@ -255,6 +307,10 @@ class BitwiseAndExpr extends BinaryBitwiseOperation, TBitwiseAndExpr {
255307
final override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
256308
}
257309

310+
private class BitwiseAndSynthExpr extends BitwiseAndExpr, BinaryOperationSynth, TBitwiseAndExprSynth {
311+
final override string getOperator() { result = "&" }
312+
}
313+
258314
/**
259315
* A bitwise OR operation.
260316
* ```rb
@@ -265,6 +321,10 @@ class BitwiseOrExpr extends BinaryBitwiseOperation, TBitwiseOrExpr {
265321
final override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
266322
}
267323

324+
private class BitwiseOrSynthExpr extends BitwiseOrExpr, BinaryOperationSynth, TBitwiseOrExprSynth {
325+
final override string getOperator() { result = "|" }
326+
}
327+
268328
/**
269329
* An XOR (exclusive OR) operation.
270330
* ```rb
@@ -275,6 +335,10 @@ class BitwiseXorExpr extends BinaryBitwiseOperation, TBitwiseXorExpr {
275335
final override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }
276336
}
277337

338+
private class BitwiseXorSynthExpr extends BitwiseXorExpr, BinaryOperationSynth, TBitwiseXorExprSynth {
339+
final override string getOperator() { result = "^" }
340+
}
341+
278342
/**
279343
* A comparison operation. That is, either an equality operation or a
280344
* relational operation.
@@ -455,17 +519,25 @@ class Assignment extends Operation, TAssignment {
455519
* ```
456520
*/
457521
class AssignExpr extends Assignment, TAssignExpr {
522+
final override string getOperator() { result = "=" }
523+
524+
final override string getAPrimaryQlClass() { result = "AssignExpr" }
525+
}
526+
527+
private class AssignExprReal extends AssignExpr, TAssignExprReal {
458528
private Generated::Assignment g;
459529

460-
AssignExpr() { this = TAssignExpr(g) }
530+
AssignExprReal() { this = TAssignExprReal(g) }
461531

462532
final override Pattern getLeftOperand() { toGenerated(result) = g.getLeft() }
463533

464534
final override Expr getRightOperand() { toGenerated(result) = g.getRight() }
535+
}
465536

466-
final override string getOperator() { result = "=" }
537+
private class AssignExprSynth extends AssignExpr, TAssignExprSynth {
538+
final override Pattern getLeftOperand() { synthChild(this, 0, result) }
467539

468-
override string getAPrimaryQlClass() { result = "AssignExpr" }
540+
final override Expr getRightOperand() { synthChild(this, 1, result) }
469541
}
470542

471543
/**

0 commit comments

Comments
 (0)