Skip to content

Commit

Permalink
[ruby] Fixed Pseudo-Variables as Literals (#4840)
Browse files Browse the repository at this point in the history
Although the parser rule for picking up pseudo-variables seems fine, it may sometimes choose to represent it as a local variable. This fixes this and adds the related tests.
  • Loading branch information
DavidBakerEffendi authored Aug 12, 2024
1 parent b766b3a commit e83cae3
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,7 @@ class RubyNodeCreator extends RubyParserBaseVisitor[RubyNode] {
case Defines.Proc | Defines.Lambda => ProcOrLambdaExpr(visit(ctx.block()).asInstanceOf[Block])(ctx.toTextSpan)
case Defines.Loop =>
DoWhileExpression(
SimpleIdentifier(Option(Defines.getBuiltInType(Defines.TrueClass)))(
ctx.methodIdentifier().toTextSpan.spanStart("true")
),
StaticLiteral(Defines.getBuiltInType(Defines.TrueClass))(ctx.methodIdentifier().toTextSpan.spanStart("true")),
ctx.block() match {
case b: RubyParser.DoBlockBlockContext =>
visit(b.doBlock().bodyStatement())
Expand Down Expand Up @@ -714,7 +712,13 @@ class RubyNodeCreator extends RubyParserBaseVisitor[RubyNode] {
}

override def visitLocalIdentifierVariable(ctx: RubyParser.LocalIdentifierVariableContext): RubyNode = {
SimpleIdentifier()(ctx.toTextSpan)
// Sometimes pseudo variables aren't given precedence in the parser, so we double-check here
ctx.getText match {
case "nil" => StaticLiteral(getBuiltInType(Defines.NilClass))(ctx.toTextSpan)
case "true" => StaticLiteral(getBuiltInType(Defines.TrueClass))(ctx.toTextSpan)
case "false" => StaticLiteral(getBuiltInType(Defines.FalseClass))(ctx.toTextSpan)
case _ => SimpleIdentifier()(ctx.toTextSpan)
}
}

override def visitClassName(ctx: RubyParser.ClassNameContext): RubyNode = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,13 @@ class CallTests extends RubyCode2CpgFixture(withPostProcessing = true) {
augeasReceiv.argument(2).asInstanceOf[FieldIdentifier].canonicalName shouldBe "open"
}

"`nil` keyword as a member access should be a literal" in {
val cpg = code("nil.to_json")
val toJson = cpg.fieldAccess.codeExact("nil.to_json").head
val nilRec = toJson.argument(1).asInstanceOf[Literal]

nilRec.code shouldBe "nil"
nilRec.lineNumber shouldBe Option(1)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ class ControlStructureTests extends RubyCode2CpgFixture {
val List(breakNode) = cpg.break.l
breakNode.code shouldBe "break"
breakNode.lineNumber shouldBe Some(8)

// `loop` is lowered as a do-while loop with a true condition
cpg.controlStructure.condition("true").size shouldBe 1
}

"`if-end` statement is represented by an `IF` CONTROL_STRUCTURE node" in {
Expand Down

0 comments on commit e83cae3

Please sign in to comment.