|
2 | 2 |
|
3 | 3 | private import codeql.ruby.AST
|
4 | 4 | private import codeql.ruby.controlflow.BasicBlocks
|
| 5 | +private import codeql.ruby.dataflow.SSA |
5 | 6 | private import ControlFlowGraph
|
6 | 7 | private import internal.ControlFlowGraphImpl
|
7 | 8 | private import internal.Splitting
|
@@ -98,6 +99,16 @@ class ExprCfgNode extends AstCfgNode {
|
98 | 99 |
|
99 | 100 | /** Gets the underlying expression. */
|
100 | 101 | Expr getExpr() { result = e }
|
| 102 | + |
| 103 | + private ExprCfgNode getSource() { |
| 104 | + exists(Ssa::WriteDefinition def | |
| 105 | + def.assigns(result) and |
| 106 | + this = def.getARead() |
| 107 | + ) |
| 108 | + } |
| 109 | + |
| 110 | + /** Gets the textual (constant) value of this expression, if any. */ |
| 111 | + string getValueText() { result = this.getSource().getValueText() } |
101 | 112 | }
|
102 | 113 |
|
103 | 114 | /** A control-flow node that wraps a return-like statement. */
|
@@ -164,7 +175,19 @@ abstract private class ExprChildMapping extends Expr {
|
164 | 175 |
|
165 | 176 | /** Provides classes for control-flow nodes that wrap AST expressions. */
|
166 | 177 | module ExprNodes {
|
167 |
| - // TODO: Add more classes |
| 178 | + private class LiteralChildMapping extends ExprChildMapping, Literal { |
| 179 | + override predicate relevantChild(Expr e) { none() } |
| 180 | + } |
| 181 | + |
| 182 | + /** A control-flow node that wraps an `ArrayLiteral` AST expression. */ |
| 183 | + class LiteralCfgNode extends ExprCfgNode { |
| 184 | + override LiteralChildMapping e; |
| 185 | + |
| 186 | + override Literal getExpr() { result = super.getExpr() } |
| 187 | + |
| 188 | + override string getValueText() { result = e.getValueText() } |
| 189 | + } |
| 190 | + |
168 | 191 | private class AssignExprChildMapping extends ExprChildMapping, AssignExpr {
|
169 | 192 | override predicate relevantChild(Expr e) { e = this.getAnOperand() }
|
170 | 193 | }
|
@@ -209,6 +232,49 @@ module ExprNodes {
|
209 | 232 |
|
210 | 233 | /** Gets the right operand of this binary operation. */
|
211 | 234 | final ExprCfgNode getRightOperand() { e.hasCfgChild(bo.getRightOperand(), this, result) }
|
| 235 | + |
| 236 | + final override string getValueText() { |
| 237 | + exists(string left, string right, string op | |
| 238 | + left = this.getLeftOperand().getValueText() and |
| 239 | + right = this.getRightOperand().getValueText() and |
| 240 | + op = this.getExpr().getOperator() |
| 241 | + | |
| 242 | + op = "+" and |
| 243 | + ( |
| 244 | + result = (left.toInt() + right.toInt()).toString() |
| 245 | + or |
| 246 | + not (exists(left.toInt()) and exists(right.toInt())) and |
| 247 | + result = (left.toFloat() + right.toFloat()).toString() |
| 248 | + or |
| 249 | + not (exists(left.toFloat()) and exists(right.toFloat())) and |
| 250 | + result = left + right |
| 251 | + ) |
| 252 | + or |
| 253 | + op = "-" and |
| 254 | + ( |
| 255 | + result = (left.toInt() - right.toInt()).toString() |
| 256 | + or |
| 257 | + not (exists(left.toInt()) and exists(right.toInt())) and |
| 258 | + result = (left.toFloat() - right.toFloat()).toString() |
| 259 | + ) |
| 260 | + or |
| 261 | + op = "*" and |
| 262 | + ( |
| 263 | + result = (left.toInt() * right.toInt()).toString() |
| 264 | + or |
| 265 | + not (exists(left.toInt()) and exists(right.toInt())) and |
| 266 | + result = (left.toFloat() * right.toFloat()).toString() |
| 267 | + ) |
| 268 | + or |
| 269 | + op = "/" and |
| 270 | + ( |
| 271 | + result = (left.toInt() / right.toInt()).toString() |
| 272 | + or |
| 273 | + not (exists(left.toInt()) and exists(right.toInt())) and |
| 274 | + result = (left.toFloat() / right.toFloat()).toString() |
| 275 | + ) |
| 276 | + ) |
| 277 | + } |
212 | 278 | }
|
213 | 279 |
|
214 | 280 | private class BlockArgumentChildMapping extends ExprChildMapping, BlockArgument {
|
|
0 commit comments