mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Ruby: desugar one-line pattern matches
This commit is contained in:
@@ -478,15 +478,11 @@ class WhenClause extends AstNode, TWhenClause {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
class InClause extends AstNode, TInClause {
|
||||
private Ruby::InClause g;
|
||||
|
||||
InClause() { this = TInClause(g) }
|
||||
|
||||
class InClause extends AstNode instanceof InClauseImpl {
|
||||
final override string getAPrimaryQlClass() { result = "InClause" }
|
||||
|
||||
/** Gets the body of this case-in expression. */
|
||||
final Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
final Stmt getBody() { result = super.getBody() }
|
||||
|
||||
/**
|
||||
* Gets the pattern in this case-in expression. In the
|
||||
@@ -498,7 +494,7 @@ class InClause extends AstNode, TInClause {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final CasePattern getPattern() { toGenerated(result) = g.getPattern() }
|
||||
final CasePattern getPattern() { result = super.getPattern() }
|
||||
|
||||
/**
|
||||
* Gets the pattern guard condition in this case-in expression. In the
|
||||
@@ -510,7 +506,7 @@ class InClause extends AstNode, TInClause {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
final Expr getCondition() { toGenerated(result) = g.getGuard().getAFieldOrChild() }
|
||||
final Expr getCondition() { result = super.getCondition() }
|
||||
|
||||
/**
|
||||
* Holds if the pattern guard in this case-in expression is an `if` condition. For example:
|
||||
@@ -520,7 +516,7 @@ class InClause extends AstNode, TInClause {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
predicate hasIfCondition() { g.getGuard() instanceof Ruby::IfGuard }
|
||||
predicate hasIfCondition() { super.hasIfCondition() }
|
||||
|
||||
/**
|
||||
* Holds if the pattern guard in this case-in expression is an `unless` condition. For example:
|
||||
@@ -530,12 +526,12 @@ class InClause extends AstNode, TInClause {
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
predicate hasUnlessCondition() { g.getGuard() instanceof Ruby::UnlessGuard }
|
||||
predicate hasUnlessCondition() { super.hasUnlessCondition() }
|
||||
|
||||
final override string toString() { result = "in ... then ..." }
|
||||
|
||||
final override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
result = AstNode.super.getAChild(pred)
|
||||
or
|
||||
pred = "getBody" and result = this.getBody()
|
||||
or
|
||||
|
||||
@@ -97,12 +97,16 @@ private module Cached {
|
||||
} or
|
||||
TBlockArgument(Ruby::BlockArgument g) or
|
||||
TBlockParameter(Ruby::BlockParameter g) or
|
||||
TBooleanLiteralSynth(Ast::AstNode parent, int i, boolean value) {
|
||||
mkSynthChild(BooleanLiteralKind(value), parent, i)
|
||||
} or
|
||||
TBraceBlockSynth(Ast::AstNode parent, int i) { mkSynthChild(BraceBlockKind(), parent, i) } or
|
||||
TBraceBlockReal(Ruby::Block g) { not g.getParent() instanceof Ruby::Lambda } or
|
||||
TBreakStmt(Ruby::Break g) or
|
||||
TCaseEqExpr(Ruby::Binary g) { g instanceof @ruby_binary_equalequalequal } or
|
||||
TCaseExpr(Ruby::Case g) or
|
||||
TCaseMatch(Ruby::CaseMatch g) or
|
||||
TCaseMatchReal(Ruby::CaseMatch g) or
|
||||
TCaseMatchSynth(Ast::AstNode parent, int i) { mkSynthChild(CaseMatchKind(), parent, i) } or
|
||||
TCharacterLiteral(Ruby::Character g) or
|
||||
TClassDeclaration(Ruby::Class g) or
|
||||
TClassVariableAccessReal(Ruby::ClassVariable g, Ast::ClassVariable v) {
|
||||
@@ -130,6 +134,7 @@ private module Cached {
|
||||
TDoBlock(Ruby::DoBlock g) { not g.getParent() instanceof Ruby::Lambda } or
|
||||
TElementReference(Ruby::ElementReference g) or
|
||||
TElse(Ruby::Else g) or
|
||||
TElseSynth(Ast::AstNode parent, int i) { mkSynthChild(ElseKind(), parent, i) } or
|
||||
TElsif(Ruby::Elsif g) or
|
||||
TEmptyStmt(Ruby::EmptyStatement g) or
|
||||
TEncoding(Ruby::Encoding g) or
|
||||
@@ -168,7 +173,8 @@ private module Cached {
|
||||
TIfReal(Ruby::If g) or
|
||||
TIfSynth(Ast::AstNode parent, int i) { mkSynthChild(IfKind(), parent, i) } or
|
||||
TIfModifierExpr(Ruby::IfModifier g) or
|
||||
TInClause(Ruby::InClause g) or
|
||||
TInClauseReal(Ruby::InClause g) or
|
||||
TInClauseSynth(Ast::AstNode parent, int i) { mkSynthChild(InClauseKind(), parent, i) } or
|
||||
TInstanceVariableAccessReal(Ruby::InstanceVariable g, Ast::InstanceVariable v) {
|
||||
InstanceVariableAccess::range(g, v)
|
||||
} or
|
||||
@@ -346,7 +352,7 @@ private module Cached {
|
||||
TAssignMulExpr or TAssignRShiftExpr or TAssignSubExpr or TBareStringLiteral or
|
||||
TBareSymbolLiteral or TBeginBlock or TBeginExpr or TBitwiseAndExprReal or
|
||||
TBitwiseOrExprReal or TBitwiseXorExprReal or TBlockArgument or TBlockParameter or
|
||||
TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCaseMatch or
|
||||
TBraceBlockReal or TBreakStmt or TCaseEqExpr or TCaseExpr or TCaseMatchReal or
|
||||
TCharacterLiteral or TClassDeclaration or TClassVariableAccessReal or TComplementExpr or
|
||||
TComplexLiteral or TDefinedExpr or TDelimitedSymbolLiteral or TDestructuredLeftAssignment or
|
||||
TDestructuredParameter or TDivExprReal or TDo or TDoBlock or TElementReference or TElse or
|
||||
@@ -355,7 +361,7 @@ private module Cached {
|
||||
TForwardArgument or TGEExpr or TGTExpr or TGlobalVariableAccessReal or
|
||||
THashKeySymbolLiteral or THashLiteral or THashPattern or THashSplatExpr or
|
||||
THashSplatNilParameter or THashSplatParameter or THereDoc or TIdentifierMethodCall or
|
||||
TIfReal or TIfModifierExpr or TInClause or TInstanceVariableAccessReal or
|
||||
TIfReal or TIfModifierExpr or TInClauseReal or TInstanceVariableAccessReal or
|
||||
TIntegerLiteralReal or TKeywordParameter or TLEExpr or TLShiftExprReal or TLTExpr or
|
||||
TLambda or TLeftAssignmentList or TLine or TLocalVariableAccessReal or
|
||||
TLogicalAndExprReal or TLogicalOrExprReal or TMethod or TMatchPattern or
|
||||
@@ -377,14 +383,14 @@ private module Cached {
|
||||
|
||||
class TAstNodeSynth =
|
||||
TAddExprSynth or TAssignExprSynth or TBitwiseAndExprSynth or TBitwiseOrExprSynth or
|
||||
TBitwiseXorExprSynth or TBraceBlockSynth or TClassVariableAccessSynth or
|
||||
TConstantReadAccessSynth or TConstantWriteAccessSynth or TDivExprSynth or
|
||||
TExponentExprSynth or TGlobalVariableAccessSynth or TIfSynth or
|
||||
TInstanceVariableAccessSynth or TIntegerLiteralSynth or TLShiftExprSynth or
|
||||
TLocalVariableAccessSynth or TLogicalAndExprSynth or TLogicalOrExprSynth or
|
||||
TMethodCallSynth or TModuloExprSynth or TMulExprSynth or TNilLiteralSynth or
|
||||
TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or TSimpleParameterSynth or
|
||||
TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth;
|
||||
TBitwiseXorExprSynth or TBraceBlockSynth or TBooleanLiteralSynth or TCaseMatchSynth or
|
||||
TClassVariableAccessSynth or TConstantReadAccessSynth or TConstantWriteAccessSynth or
|
||||
TDivExprSynth or TElseSynth or TExponentExprSynth or TGlobalVariableAccessSynth or
|
||||
TIfSynth or TInClauseSynth or TInstanceVariableAccessSynth or TIntegerLiteralSynth or
|
||||
TLShiftExprSynth or TLocalVariableAccessSynth or TLogicalAndExprSynth or
|
||||
TLogicalOrExprSynth or TMethodCallSynth or TModuloExprSynth or TMulExprSynth or
|
||||
TNilLiteralSynth or TRShiftExprSynth or TRangeLiteralSynth or TSelfSynth or
|
||||
TSimpleParameterSynth or TSplatExprSynth or TStmtSequenceSynth or TSubExprSynth;
|
||||
|
||||
/**
|
||||
* Gets the underlying TreeSitter entity for a given AST node. This does not
|
||||
@@ -426,7 +432,7 @@ private module Cached {
|
||||
n = TBreakStmt(result) or
|
||||
n = TCaseEqExpr(result) or
|
||||
n = TCaseExpr(result) or
|
||||
n = TCaseMatch(result) or
|
||||
n = TCaseMatchReal(result) or
|
||||
n = TCharacterLiteral(result) or
|
||||
n = TClassDeclaration(result) or
|
||||
n = TClassVariableAccessReal(result, _) or
|
||||
@@ -467,7 +473,7 @@ private module Cached {
|
||||
n = TIdentifierMethodCall(result) or
|
||||
n = TIfModifierExpr(result) or
|
||||
n = TIfReal(result) or
|
||||
n = TInClause(result) or
|
||||
n = TInClauseReal(result) or
|
||||
n = TInstanceVariableAccessReal(result, _) or
|
||||
n = TIntegerLiteralReal(result) or
|
||||
n = TKeywordParameter(result) or
|
||||
@@ -567,8 +573,12 @@ private module Cached {
|
||||
or
|
||||
result = TBitwiseXorExprSynth(parent, i)
|
||||
or
|
||||
result = TBooleanLiteralSynth(parent, i, _)
|
||||
or
|
||||
result = TBraceBlockSynth(parent, i)
|
||||
or
|
||||
result = TCaseMatchSynth(parent, i)
|
||||
or
|
||||
result = TClassVariableAccessSynth(parent, i, _)
|
||||
or
|
||||
result = TConstantReadAccessSynth(parent, i, _)
|
||||
@@ -577,12 +587,16 @@ private module Cached {
|
||||
or
|
||||
result = TDivExprSynth(parent, i)
|
||||
or
|
||||
result = TElseSynth(parent, i)
|
||||
or
|
||||
result = TExponentExprSynth(parent, i)
|
||||
or
|
||||
result = TGlobalVariableAccessSynth(parent, i, _)
|
||||
or
|
||||
result = TIfSynth(parent, i)
|
||||
or
|
||||
result = TInClauseSynth(parent, i)
|
||||
or
|
||||
result = TInstanceVariableAccessSynth(parent, i, _)
|
||||
or
|
||||
result = TIntegerLiteralSynth(parent, i, _)
|
||||
@@ -673,8 +687,12 @@ TAstNodeReal fromGenerated(Ruby::AstNode n) { n = toGenerated(result) }
|
||||
|
||||
class TCall = TMethodCall or TYieldCall;
|
||||
|
||||
class TCaseMatch = TCaseMatchReal or TCaseMatchSynth;
|
||||
|
||||
class TCase = TCaseExpr or TCaseMatch;
|
||||
|
||||
class TInClause = TInClauseReal or TInClauseSynth;
|
||||
|
||||
class TMethodCall =
|
||||
TMethodCallSynth or TIdentifierMethodCall or TRegularMethodCall or TElementReference or
|
||||
TSuperCall or TUnaryOperation or TBinaryOperation;
|
||||
@@ -685,7 +703,7 @@ class TConstantAccess =
|
||||
TTokenConstantAccess or TScopeResolutionConstantAccess or TNamespace or
|
||||
TConstantReadAccessSynth or TConstantWriteAccessSynth;
|
||||
|
||||
class TControlExpr = TConditionalExpr or TCaseExpr or TCaseMatch or TLoop;
|
||||
class TControlExpr = TConditionalExpr or TCaseExpr or TCaseMatchReal or TCaseMatchSynth or TLoop;
|
||||
|
||||
class TConditionalExpr =
|
||||
TIfExpr or TUnlessExpr or TIfModifierExpr or TUnlessModifierExpr or TTernaryIfExpr;
|
||||
@@ -711,8 +729,9 @@ class TExpr =
|
||||
class TSplatExpr = TSplatExprReal or TSplatExprSynth;
|
||||
|
||||
class TStmtSequence =
|
||||
TBeginBlock or TEndBlock or TThen or TElse or TDo or TEnsure or TStringInterpolationComponent or
|
||||
TBlock or TBodyStmt or TParenthesizedExpr or TStmtSequenceSynth;
|
||||
TBeginBlock or TEndBlock or TThen or TElse or TElseSynth or TDo or TEnsure or
|
||||
TStringInterpolationComponent or TBlock or TBodyStmt or TParenthesizedExpr or
|
||||
TStmtSequenceSynth;
|
||||
|
||||
class TBodyStmt = TBeginExpr or TModuleBase or TMethod or TLambda or TDoBlock or TSingletonMethod;
|
||||
|
||||
@@ -727,7 +746,7 @@ class TNumericLiteral = TIntegerLiteral or TFloatLiteral or TRationalLiteral or
|
||||
|
||||
class TIntegerLiteral = TIntegerLiteralReal or TIntegerLiteralSynth;
|
||||
|
||||
class TBooleanLiteral = TTrueLiteral or TFalseLiteral;
|
||||
class TBooleanLiteral = TTrueLiteral or TFalseLiteral or TBooleanLiteralSynth;
|
||||
|
||||
class TStringTextComponentNonRegexp =
|
||||
TStringTextComponentNonRegexpStringOrHeredocContent or
|
||||
|
||||
@@ -21,10 +21,10 @@ class CaseWhenClause extends CaseExprImpl, TCaseExpr {
|
||||
}
|
||||
}
|
||||
|
||||
class CaseMatch extends CaseExprImpl, TCaseMatch {
|
||||
class CaseMatch extends CaseExprImpl, TCaseMatchReal {
|
||||
private Ruby::CaseMatch g;
|
||||
|
||||
CaseMatch() { this = TCaseMatch(g) }
|
||||
CaseMatch() { this = TCaseMatchReal(g) }
|
||||
|
||||
final override Expr getValue() { toGenerated(result) = g.getValue() }
|
||||
|
||||
@@ -34,3 +34,53 @@ class CaseMatch extends CaseExprImpl, TCaseMatch {
|
||||
n = count(g.getClauses(_)) and toGenerated(result) = g.getElse()
|
||||
}
|
||||
}
|
||||
|
||||
class CaseMatchSynth extends CaseExprImpl, TCaseMatchSynth {
|
||||
CaseMatchSynth() { this = TCaseMatchSynth(_, _) }
|
||||
|
||||
final override Expr getValue() { synthChild(this, 0, result) }
|
||||
|
||||
final override AstNode getBranch(int n) { n >= 0 and synthChild(this, n + 1, result) }
|
||||
}
|
||||
|
||||
abstract class InClauseImpl extends AstNode, TInClause {
|
||||
abstract Stmt getBody();
|
||||
|
||||
abstract CasePattern getPattern();
|
||||
|
||||
Expr getCondition() { none() }
|
||||
|
||||
predicate hasIfCondition() { none() }
|
||||
|
||||
predicate hasUnlessCondition() { none() }
|
||||
}
|
||||
|
||||
class InClauseReal extends InClauseImpl, TInClauseReal {
|
||||
private Ruby::InClause g;
|
||||
|
||||
InClauseReal() { this = TInClauseReal(g) }
|
||||
|
||||
final override Stmt getBody() { toGenerated(result) = g.getBody() }
|
||||
|
||||
final override CasePattern getPattern() { toGenerated(result) = g.getPattern() }
|
||||
|
||||
final override Expr getCondition() { toGenerated(result) = g.getGuard().getAFieldOrChild() }
|
||||
|
||||
final override predicate hasIfCondition() { g.getGuard() instanceof Ruby::IfGuard }
|
||||
|
||||
final override predicate hasUnlessCondition() { g.getGuard() instanceof Ruby::UnlessGuard }
|
||||
}
|
||||
|
||||
class InClauseSynth extends InClauseImpl, TInClauseSynth {
|
||||
InClauseSynth() { this = TInClauseSynth(_, _) }
|
||||
|
||||
final override Stmt getBody() { synthChild(this, 1, result) }
|
||||
|
||||
final override CasePattern getPattern() { synthChild(this, 0, result) }
|
||||
|
||||
final override Expr getCondition() { none() }
|
||||
|
||||
final override predicate hasIfCondition() { none() }
|
||||
|
||||
final override predicate hasUnlessCondition() { none() }
|
||||
}
|
||||
|
||||
@@ -29,6 +29,14 @@ class Else extends StmtSequence, TElse {
|
||||
final override string toString() { result = "else ..." }
|
||||
}
|
||||
|
||||
class ElseSynth extends StmtSequence, TElseSynth {
|
||||
ElseSynth() { this = TElseSynth(_, _) }
|
||||
|
||||
override Stmt getStmt(int n) { synthChild(this, n, result) }
|
||||
|
||||
final override string toString() { result = "else ..." }
|
||||
}
|
||||
|
||||
class Do extends StmtSequence, TDo {
|
||||
private Ruby::Do g;
|
||||
|
||||
|
||||
@@ -149,6 +149,12 @@ class FalseLiteral extends BooleanLiteralImpl, TFalseLiteral {
|
||||
final override boolean getValue() { result = false }
|
||||
}
|
||||
|
||||
class BooleanLiteralSynth extends BooleanLiteralImpl, TBooleanLiteralSynth {
|
||||
final override string toString() { result = this.getValue().toString() }
|
||||
|
||||
final override boolean getValue() { this = TBooleanLiteralSynth(_, _, result) }
|
||||
}
|
||||
|
||||
class EncodingLiteralImpl extends Expr, TEncoding {
|
||||
private Ruby::Encoding g;
|
||||
|
||||
|
||||
@@ -16,12 +16,16 @@ newtype SynthKind =
|
||||
BitwiseAndExprKind() or
|
||||
BitwiseOrExprKind() or
|
||||
BitwiseXorExprKind() or
|
||||
BooleanLiteralKind(boolean value) { value = true or value = false } or
|
||||
BraceBlockKind() or
|
||||
CaseMatchKind() or
|
||||
ClassVariableAccessKind(ClassVariable v) or
|
||||
DivExprKind() or
|
||||
ElseKind() or
|
||||
ExponentExprKind() or
|
||||
GlobalVariableAccessKind(GlobalVariable v) or
|
||||
IfKind() or
|
||||
InClauseKind() or
|
||||
InstanceVariableAccessKind(InstanceVariable v) or
|
||||
IntegerLiteralKind(int i) { i in [-1000 .. 1000] } or
|
||||
LShiftExprKind() or
|
||||
@@ -1497,3 +1501,102 @@ private module SafeNavigationCallDesugar {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module TestPatternDesugar {
|
||||
/**
|
||||
* ```rb
|
||||
* expr in pattern
|
||||
* ```
|
||||
* desugars to
|
||||
*
|
||||
* ```rb
|
||||
* case expr
|
||||
* in pattern then true
|
||||
* else false
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate testPatternSynthesis(AstNode parent, int i, Child child) {
|
||||
exists(TestPattern test |
|
||||
parent = test and
|
||||
i = -1 and
|
||||
child = SynthChild(CaseMatchKind())
|
||||
or
|
||||
exists(TCaseMatchSynth case | case = TCaseMatchSynth(test, -1) |
|
||||
parent = case and
|
||||
(
|
||||
child = childRef(test.getValue()) and i = 0
|
||||
or
|
||||
child = SynthChild(InClauseKind()) and i = 1
|
||||
or
|
||||
child = SynthChild(ElseKind()) and i = 2
|
||||
)
|
||||
or
|
||||
parent = TInClauseSynth(case, 1) and
|
||||
(
|
||||
child = childRef(test.getPattern()) and
|
||||
i = 0
|
||||
or
|
||||
child = SynthChild(BooleanLiteralKind(true)) and i = 1
|
||||
)
|
||||
or
|
||||
parent = TElseSynth(case, 2) and
|
||||
child = SynthChild(BooleanLiteralKind(false)) and
|
||||
i = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private class TestPatternSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
testPatternSynthesis(parent, i, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module MatchPatternDesugar {
|
||||
/**
|
||||
* ```rb
|
||||
* expr => pattern
|
||||
* ```
|
||||
* desugars to
|
||||
*
|
||||
* ```rb
|
||||
* case expr
|
||||
* in pattern then nil
|
||||
* end
|
||||
* ```
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate matchPatternSynthesis(AstNode parent, int i, Child child) {
|
||||
exists(MatchPattern test |
|
||||
parent = test and
|
||||
i = -1 and
|
||||
child = SynthChild(CaseMatchKind())
|
||||
or
|
||||
exists(TCaseMatchSynth case | case = TCaseMatchSynth(test, -1) |
|
||||
parent = case and
|
||||
(
|
||||
child = childRef(test.getValue()) and i = 0
|
||||
or
|
||||
child = SynthChild(InClauseKind()) and i = 1
|
||||
)
|
||||
or
|
||||
parent = TInClauseSynth(case, 1) and
|
||||
(
|
||||
child = childRef(test.getPattern()) and
|
||||
i = 0
|
||||
or
|
||||
child = SynthChild(NilLiteralKind()) and i = 1
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private class MatchPatternSynthesis extends Synthesis {
|
||||
final override predicate child(AstNode parent, int i, Child child) {
|
||||
matchPatternSynthesis(parent, i, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user