From 2035bc4d3a3524484df01c55cd75f51e0bcc156a Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Thu, 4 Feb 2021 11:35:55 +0100 Subject: [PATCH] AST: add ParenthesizedExpr --- ql/src/codeql_ruby/ast/Expr.qll | 39 +++++++++++++++- ql/src/codeql_ruby/ast/internal/Expr.qll | 8 ++++ .../ast/control/CaseExpr.expected | 16 +++---- .../ast/control/ConditionalExpr.expected | 42 +++++++++--------- .../controlflow/graph/Cfg.expected | 44 +++++++++---------- 5 files changed, 97 insertions(+), 52 deletions(-) diff --git a/ql/src/codeql_ruby/ast/Expr.qll b/ql/src/codeql_ruby/ast/Expr.qll index e288e83b80c..120a498fe94 100644 --- a/ql/src/codeql_ruby/ast/Expr.qll +++ b/ql/src/codeql_ruby/ast/Expr.qll @@ -124,7 +124,15 @@ class ExprSequence extends Expr { override string getAPrimaryQlClass() { result = "ExprSequence" } - override string toString() { result = "...; ..." } + override string toString() { + exists(int c | c = this.getNumberOfExpressions() | + c = 0 and result = ";" + or + c = 1 and result = this.getExpr(0).toString() + or + c > 1 and result = "...; ..." + ) + } /** Gets the `n`th expression in this sequence. */ final Expr getExpr(int n) { result = range.getExpr(n) } @@ -151,6 +159,35 @@ class BodyStatement extends ExprSequence { override BodyStatement::Range range; } +/** + * A parenthesized expression sequence, typically containing a single expression: + * ```rb + * (x + 1) + * ``` + * However, they can also contain multiple expressions (the value of the parenthesized + * expression is the last expression): + * ```rb + * (foo; bar) + * ``` + * or even an empty sequence (value is `nil`): + * ```rb + * () + * ``` + */ +class ParenthesizedExpr extends ExprSequence, @parenthesized_statements { + final override ParenthesizedExpr::Range range; + + final override string getAPrimaryQlClass() { result = "ParenthesizedExpr" } + + final override string toString() { + exists(int c | c = this.getNumberOfExpressions() | + c = 0 and result = "()" + or + c > 0 and result = "(" + ExprSequence.super.toString() + ")" + ) + } +} + /** * A scope resolution, typically used to access constants defined in a class or * module. diff --git a/ql/src/codeql_ruby/ast/internal/Expr.qll b/ql/src/codeql_ruby/ast/internal/Expr.qll index 3483cea9882..6786f2bb9f9 100644 --- a/ql/src/codeql_ruby/ast/internal/Expr.qll +++ b/ql/src/codeql_ruby/ast/internal/Expr.qll @@ -172,6 +172,14 @@ module BodyStatement { abstract class Range extends ExprSequence::Range { } } +module ParenthesizedExpr { + class Range extends ExprSequence::Range, @parenthesized_statements { + final override Generated::ParenthesizedStatements generated; + + final override Expr getExpr(int n) { result = generated.getChild(n) } + } +} + module ThenExpr { class Range extends ExprSequence::Range, @then { final override Generated::Then generated; diff --git a/ql/test/library-tests/ast/control/CaseExpr.expected b/ql/test/library-tests/ast/control/CaseExpr.expected index 387a17efe72..bf54ec6f095 100644 --- a/ql/test/library-tests/ast/control/CaseExpr.expected +++ b/ql/test/library-tests/ast/control/CaseExpr.expected @@ -3,20 +3,20 @@ caseValues caseNoValues | cases.rb:18:1:22:3 | case ... | caseElseBranches -| cases.rb:8:1:15:3 | case ... | cases.rb:13:1:14:7 | ...; ... | +| cases.rb:8:1:15:3 | case ... | cases.rb:13:1:14:7 | 300 | caseNoElseBranches | cases.rb:18:1:22:3 | case ... | caseWhenBranches -| cases.rb:8:1:15:3 | case ... | cases.rb:9:1:10:7 | when ... | 0 | cases.rb:9:6:9:6 | b | cases.rb:9:7:10:7 | ...; ... | -| cases.rb:8:1:15:3 | case ... | cases.rb:11:1:12:7 | when ... | 0 | cases.rb:11:6:11:6 | c | cases.rb:11:10:12:7 | ...; ... | -| cases.rb:8:1:15:3 | case ... | cases.rb:11:1:12:7 | when ... | 1 | cases.rb:11:9:11:9 | d | cases.rb:11:10:12:7 | ...; ... | -| cases.rb:18:1:22:3 | case ... | cases.rb:19:1:19:19 | when ... | 0 | cases.rb:19:6:19:10 | ... > ... | cases.rb:19:13:19:19 | ...; ... | -| cases.rb:18:1:22:3 | case ... | cases.rb:20:1:20:19 | when ... | 0 | cases.rb:20:6:20:11 | ... == ... | cases.rb:20:13:20:19 | ...; ... | -| cases.rb:18:1:22:3 | case ... | cases.rb:21:1:21:19 | when ... | 0 | cases.rb:21:6:21:10 | ... < ... | cases.rb:21:13:21:19 | ...; ... | +| cases.rb:8:1:15:3 | case ... | cases.rb:9:1:10:7 | when ... | 0 | cases.rb:9:6:9:6 | b | cases.rb:9:7:10:7 | 100 | +| cases.rb:8:1:15:3 | case ... | cases.rb:11:1:12:7 | when ... | 0 | cases.rb:11:6:11:6 | c | cases.rb:11:10:12:7 | 200 | +| cases.rb:8:1:15:3 | case ... | cases.rb:11:1:12:7 | when ... | 1 | cases.rb:11:9:11:9 | d | cases.rb:11:10:12:7 | 200 | +| cases.rb:18:1:22:3 | case ... | cases.rb:19:1:19:19 | when ... | 0 | cases.rb:19:6:19:10 | ... > ... | cases.rb:19:13:19:19 | 10 | +| cases.rb:18:1:22:3 | case ... | cases.rb:20:1:20:19 | when ... | 0 | cases.rb:20:6:20:11 | ... == ... | cases.rb:20:13:20:19 | 20 | +| cases.rb:18:1:22:3 | case ... | cases.rb:21:1:21:19 | when ... | 0 | cases.rb:21:6:21:10 | ... < ... | cases.rb:21:13:21:19 | 30 | caseAllBranches | cases.rb:8:1:15:3 | case ... | 0 | cases.rb:9:1:10:7 | when ... | | cases.rb:8:1:15:3 | case ... | 1 | cases.rb:11:1:12:7 | when ... | -| cases.rb:8:1:15:3 | case ... | 2 | cases.rb:13:1:14:7 | ...; ... | +| cases.rb:8:1:15:3 | case ... | 2 | cases.rb:13:1:14:7 | 300 | | cases.rb:18:1:22:3 | case ... | 0 | cases.rb:19:1:19:19 | when ... | | cases.rb:18:1:22:3 | case ... | 1 | cases.rb:20:1:20:19 | when ... | | cases.rb:18:1:22:3 | case ... | 2 | cases.rb:21:1:21:19 | when ... | diff --git a/ql/test/library-tests/ast/control/ConditionalExpr.expected b/ql/test/library-tests/ast/control/ConditionalExpr.expected index 6d60d833215..ce3c57f3471 100644 --- a/ql/test/library-tests/ast/control/ConditionalExpr.expected +++ b/ql/test/library-tests/ast/control/ConditionalExpr.expected @@ -1,34 +1,34 @@ conditionalExprs -| conditionals.rb:10:1:12:3 | if ... | IfExpr | conditionals.rb:10:4:10:8 | ... > ... | conditionals.rb:10:10:11:5 | ...; ... | true | -| conditionals.rb:15:1:19:3 | if ... | IfExpr | conditionals.rb:15:4:15:9 | ... == ... | conditionals.rb:15:10:16:5 | ...; ... | true | -| conditionals.rb:15:1:19:3 | if ... | IfExpr | conditionals.rb:15:4:15:9 | ... == ... | conditionals.rb:17:1:18:5 | ...; ... | false | -| conditionals.rb:22:1:30:3 | if ... | IfExpr | conditionals.rb:22:4:22:9 | ... == ... | conditionals.rb:22:11:23:5 | ...; ... | true | +| conditionals.rb:10:1:12:3 | if ... | IfExpr | conditionals.rb:10:4:10:8 | ... > ... | conditionals.rb:10:10:11:5 | c | true | +| conditionals.rb:15:1:19:3 | if ... | IfExpr | conditionals.rb:15:4:15:9 | ... == ... | conditionals.rb:15:10:16:5 | c | true | +| conditionals.rb:15:1:19:3 | if ... | IfExpr | conditionals.rb:15:4:15:9 | ... == ... | conditionals.rb:17:1:18:5 | d | false | +| conditionals.rb:22:1:30:3 | if ... | IfExpr | conditionals.rb:22:4:22:9 | ... == ... | conditionals.rb:22:11:23:5 | c | true | | conditionals.rb:22:1:30:3 | if ... | IfExpr | conditionals.rb:22:4:22:9 | ... == ... | conditionals.rb:24:1:29:5 | elsif ... | false | -| conditionals.rb:24:1:29:5 | elsif ... | IfExpr | conditionals.rb:24:7:24:12 | ... == ... | conditionals.rb:24:14:25:5 | ...; ... | true | +| conditionals.rb:24:1:29:5 | elsif ... | IfExpr | conditionals.rb:24:7:24:12 | ... == ... | conditionals.rb:24:14:25:5 | d | true | | conditionals.rb:24:1:29:5 | elsif ... | IfExpr | conditionals.rb:24:7:24:12 | ... == ... | conditionals.rb:26:1:29:5 | elsif ... | false | -| conditionals.rb:26:1:29:5 | elsif ... | IfExpr | conditionals.rb:26:7:26:12 | ... == ... | conditionals.rb:26:14:27:5 | ...; ... | true | -| conditionals.rb:26:1:29:5 | elsif ... | IfExpr | conditionals.rb:26:7:26:12 | ... == ... | conditionals.rb:28:1:29:5 | ...; ... | false | -| conditionals.rb:33:1:37:3 | if ... | IfExpr | conditionals.rb:33:4:33:9 | ... == ... | conditionals.rb:33:10:34:5 | ...; ... | true | +| conditionals.rb:26:1:29:5 | elsif ... | IfExpr | conditionals.rb:26:7:26:12 | ... == ... | conditionals.rb:26:14:27:5 | e | true | +| conditionals.rb:26:1:29:5 | elsif ... | IfExpr | conditionals.rb:26:7:26:12 | ... == ... | conditionals.rb:28:1:29:5 | f | false | +| conditionals.rb:33:1:37:3 | if ... | IfExpr | conditionals.rb:33:4:33:9 | ... == ... | conditionals.rb:33:10:34:5 | b | true | | conditionals.rb:33:1:37:3 | if ... | IfExpr | conditionals.rb:33:4:33:9 | ... == ... | conditionals.rb:35:1:36:5 | elsif ... | false | -| conditionals.rb:35:1:36:5 | elsif ... | IfExpr | conditionals.rb:35:7:35:12 | ... == ... | conditionals.rb:35:13:36:5 | ...; ... | true | -| conditionals.rb:40:1:42:3 | unless ... | UnlessExpr | conditionals.rb:40:8:40:12 | ... > ... | conditionals.rb:40:14:41:5 | ...; ... | false | -| conditionals.rb:45:1:49:3 | unless ... | UnlessExpr | conditionals.rb:45:8:45:13 | ... == ... | conditionals.rb:45:14:46:5 | ...; ... | false | -| conditionals.rb:45:1:49:3 | unless ... | UnlessExpr | conditionals.rb:45:8:45:13 | ... == ... | conditionals.rb:47:1:48:5 | ...; ... | true | +| conditionals.rb:35:1:36:5 | elsif ... | IfExpr | conditionals.rb:35:7:35:12 | ... == ... | conditionals.rb:35:13:36:5 | c | true | +| conditionals.rb:40:1:42:3 | unless ... | UnlessExpr | conditionals.rb:40:8:40:12 | ... > ... | conditionals.rb:40:14:41:5 | c | false | +| conditionals.rb:45:1:49:3 | unless ... | UnlessExpr | conditionals.rb:45:8:45:13 | ... == ... | conditionals.rb:45:14:46:5 | c | false | +| conditionals.rb:45:1:49:3 | unless ... | UnlessExpr | conditionals.rb:45:8:45:13 | ... == ... | conditionals.rb:47:1:48:5 | d | true | | conditionals.rb:52:1:52:14 | ... if ... | IfModifierExpr | conditionals.rb:52:10:52:14 | ... > ... | conditionals.rb:52:1:52:5 | ... = ... | true | | conditionals.rb:55:1:55:18 | ... unless ... | UnlessModifierExpr | conditionals.rb:55:14:55:18 | ... < ... | conditionals.rb:55:1:55:5 | ... = ... | false | | conditionals.rb:58:5:58:25 | ... ? ... : ... | TernaryIfExpr | conditionals.rb:58:5:58:9 | ... > ... | conditionals.rb:58:13:58:17 | ... + ... | true | | conditionals.rb:58:5:58:25 | ... ? ... : ... | TernaryIfExpr | conditionals.rb:58:5:58:9 | ... > ... | conditionals.rb:58:21:58:25 | ... - ... | false | ifExprs -| conditionals.rb:10:1:12:3 | if ... | IfExpr | conditionals.rb:10:4:10:8 | ... > ... | conditionals.rb:10:10:11:5 | ...; ... | (none) | false | -| conditionals.rb:15:1:19:3 | if ... | IfExpr | conditionals.rb:15:4:15:9 | ... == ... | conditionals.rb:15:10:16:5 | ...; ... | ...; ... | false | -| conditionals.rb:22:1:30:3 | if ... | IfExpr | conditionals.rb:22:4:22:9 | ... == ... | conditionals.rb:22:11:23:5 | ...; ... | elsif ... | false | -| conditionals.rb:24:1:29:5 | elsif ... | IfExpr | conditionals.rb:24:7:24:12 | ... == ... | conditionals.rb:24:14:25:5 | ...; ... | elsif ... | true | -| conditionals.rb:26:1:29:5 | elsif ... | IfExpr | conditionals.rb:26:7:26:12 | ... == ... | conditionals.rb:26:14:27:5 | ...; ... | ...; ... | true | -| conditionals.rb:33:1:37:3 | if ... | IfExpr | conditionals.rb:33:4:33:9 | ... == ... | conditionals.rb:33:10:34:5 | ...; ... | elsif ... | false | -| conditionals.rb:35:1:36:5 | elsif ... | IfExpr | conditionals.rb:35:7:35:12 | ... == ... | conditionals.rb:35:13:36:5 | ...; ... | (none) | true | +| conditionals.rb:10:1:12:3 | if ... | IfExpr | conditionals.rb:10:4:10:8 | ... > ... | conditionals.rb:10:10:11:5 | c | (none) | false | +| conditionals.rb:15:1:19:3 | if ... | IfExpr | conditionals.rb:15:4:15:9 | ... == ... | conditionals.rb:15:10:16:5 | c | d | false | +| conditionals.rb:22:1:30:3 | if ... | IfExpr | conditionals.rb:22:4:22:9 | ... == ... | conditionals.rb:22:11:23:5 | c | elsif ... | false | +| conditionals.rb:24:1:29:5 | elsif ... | IfExpr | conditionals.rb:24:7:24:12 | ... == ... | conditionals.rb:24:14:25:5 | d | elsif ... | true | +| conditionals.rb:26:1:29:5 | elsif ... | IfExpr | conditionals.rb:26:7:26:12 | ... == ... | conditionals.rb:26:14:27:5 | e | f | true | +| conditionals.rb:33:1:37:3 | if ... | IfExpr | conditionals.rb:33:4:33:9 | ... == ... | conditionals.rb:33:10:34:5 | b | elsif ... | false | +| conditionals.rb:35:1:36:5 | elsif ... | IfExpr | conditionals.rb:35:7:35:12 | ... == ... | conditionals.rb:35:13:36:5 | c | (none) | true | unlessExprs -| conditionals.rb:40:1:42:3 | unless ... | UnlessExpr | conditionals.rb:40:8:40:12 | ... > ... | conditionals.rb:40:14:41:5 | ...; ... | (none) | -| conditionals.rb:45:1:49:3 | unless ... | UnlessExpr | conditionals.rb:45:8:45:13 | ... == ... | conditionals.rb:45:14:46:5 | ...; ... | ...; ... | +| conditionals.rb:40:1:42:3 | unless ... | UnlessExpr | conditionals.rb:40:8:40:12 | ... > ... | conditionals.rb:40:14:41:5 | c | (none) | +| conditionals.rb:45:1:49:3 | unless ... | UnlessExpr | conditionals.rb:45:8:45:13 | ... == ... | conditionals.rb:45:14:46:5 | c | d | ifModifierExprs | conditionals.rb:52:1:52:14 | ... if ... | IfModifierExpr | conditionals.rb:52:10:52:14 | ... > ... | conditionals.rb:52:1:52:5 | ... = ... | unlessModifierExprs diff --git a/ql/test/library-tests/controlflow/graph/Cfg.expected b/ql/test/library-tests/controlflow/graph/Cfg.expected index 20dcc3a522e..319ae01c0bf 100644 --- a/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -514,11 +514,11 @@ case.rb: #-----| match -> call to x2 #-----| no-match -> when ... -# 3| ParenthesizedStatements +# 3| (if ...) #-----| -> exit if_in_case (normal) # 3| if ... -#-----| -> ParenthesizedStatements +#-----| -> (if ...) # 3| call to x2 #-----| false -> if ... @@ -1313,14 +1313,14 @@ cfg.rb: # 108| puts #-----| -> < call to puts # 108| < call to table # 108| HeredocBody -#-----| -> ParenthesizedStatements +#-----| -> () # 109| Interpolation #-----| -> call to type @@ -1446,7 +1446,7 @@ cfg.rb: # 126| last #-----| -> ... = ... -# 126| ParenthesizedStatements +# 126| (...; ...) #-----| -> last # 126| 2 @@ -1456,7 +1456,7 @@ cfg.rb: #-----| -> 7 # 126| 7 -#-----| -> ParenthesizedStatements +#-----| -> (...; ...) # 127| ... = ... #-----| -> 1 @@ -1888,7 +1888,7 @@ cfg.rb: # 176| ... until ... #-----| -> i -# 176| ParenthesizedStatements +# 176| (...; ...) #-----| -> i # 176| call to puts @@ -1901,7 +1901,7 @@ cfg.rb: #-----| -> call to puts # 176| ... += ... -#-----| -> ParenthesizedStatements +#-----| -> (...; ...) # 176| i #-----| -> 1 @@ -1978,7 +1978,7 @@ cfg.rb: # 185| ... while ... #-----| -> i -# 185| ParenthesizedStatements +# 185| (...; ...) #-----| -> i # 185| call to puts @@ -1991,7 +1991,7 @@ cfg.rb: #-----| -> call to puts # 185| ... -= ... -#-----| -> ParenthesizedStatements +#-----| -> (...; ...) # 185| i #-----| -> 1 @@ -2220,15 +2220,15 @@ ifs.rb: # 4| [true] ! ... #-----| true -> [true] ... and ... -# 4| [false] ParenthesizedStatements +# 4| [false] (... == ...) #-----| false -> [true] ! ... -# 4| [true] ParenthesizedStatements +# 4| [true] (... == ...) #-----| true -> [false] ! ... # 4| ... == ... -#-----| false -> [false] ParenthesizedStatements -#-----| true -> [true] ParenthesizedStatements +#-----| false -> [false] (... == ...) +#-----| true -> [true] (... == ...) # 4| x #-----| -> 5 @@ -2374,17 +2374,17 @@ ifs.rb: # 29| ... ? ... : ... #-----| -> Return -# 29| [false] ParenthesizedStatements +# 29| [false] (... ? ... : ...) #-----| false -> !b2 || !b3 -# 29| [true] ParenthesizedStatements +# 29| [true] (... ? ... : ...) #-----| true -> b2 || b3 # 29| [false] ... ? ... : ... -#-----| false -> [false] ParenthesizedStatements +#-----| false -> [false] (... ? ... : ...) # 29| [true] ... ? ... : ... -#-----| true -> [true] ParenthesizedStatements +#-----| true -> [true] (... ? ... : ...) # 29| b1 #-----| true -> b2 @@ -2428,17 +2428,17 @@ ifs.rb: # 33| if ... #-----| -> exit m5 (normal) -# 33| [false] ParenthesizedStatements +# 33| [false] (if ...) #-----| false -> !b2 || !b4 || !b5 -# 33| [true] ParenthesizedStatements +# 33| [true] (if ...) #-----| true -> b2 || b4 || b5 # 33| [false] if ... -#-----| false -> [false] ParenthesizedStatements +#-----| false -> [false] (if ...) # 33| [true] if ... -#-----| true -> [true] ParenthesizedStatements +#-----| true -> [true] (if ...) # 33| b1 #-----| true -> b2