diff --git a/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/parser/RubyJsonHelpers.scala b/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/parser/RubyJsonHelpers.scala index 0f2577a6139c..efe70d7cc8ac 100644 --- a/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/parser/RubyJsonHelpers.scala +++ b/joern-cli/frontends/rubysrc2cpg/src/main/scala/io/joern/rubysrc2cpg/parser/RubyJsonHelpers.scala @@ -4,6 +4,7 @@ import io.joern.rubysrc2cpg.astcreation.RubyIntermediateAst.{ AliasStatement, AllowedTypeDeclarationChild, ArrayLiteral, + ArrayParameter, ClassFieldIdentifier, ControlFlowStatement, DefaultMultipleAssignment, @@ -12,6 +13,7 @@ import io.joern.rubysrc2cpg.astcreation.RubyIntermediateAst.{ IfExpression, MemberAccess, MethodDeclaration, + ProcParameter, ProcedureDeclaration, RubyCall, RubyExpression, @@ -354,29 +356,22 @@ object RubyJsonHelpers { case x => List(x) } - val methodParamMap = stmts.collect { case method: ProcedureDeclaration => - method.methodName -> method.parameters - }.toMap - val transformedStmts = stmts.map { - case alias: AliasStatement if methodParamMap.contains(alias.oldName) => - val aliasingMethodParams = methodParamMap(alias.oldName) - val argsCode = aliasingMethodParams.map(_.text).mkString(", ") - val callCode = s"${alias.oldName}($argsCode)" - - val forwardingCall = SimpleCall( - SimpleIdentifier(None)(alias.span.spanStart(alias.oldName)), - aliasingMethodParams.map { x => SimpleIdentifier(None)(alias.span.spanStart(x.span.text)) } - )(alias.span.spanStart(callCode)) - val aliasMethodBody = StatementList(forwardingCall :: Nil)(alias.span.spanStart(callCode)) - MethodDeclaration(alias.newName, aliasingMethodParams, aliasMethodBody)( - alias.span.spanStart(s"def ${alias.newName}($argsCode)") + case alias: AliasStatement => + val span = alias.span + val forwardingCallTarget = SimpleIdentifier(None)(span.spanStart(alias.oldName)) + val forwardedArgs = SplattingRubyNode(SimpleIdentifier()(span.spanStart("args")))(span.spanStart("*args")) + val forwardedBlock = SimpleIdentifier()(span.spanStart("&block")) + val forwardingCall = SimpleCall(forwardingCallTarget, forwardedArgs :: forwardedBlock :: Nil)( + span.spanStart(s"${alias.oldName}(*args, &block)") ) - case alias: AliasStatement => - logger.warn(s"Unable to correctly lower aliased method ${alias.oldName} (aliased method not found)") - val forwardingCall = SimpleCall(SimpleIdentifier(None)(alias.span.spanStart(alias.oldName)), Nil)(alias.span) - MethodDeclaration(alias.newName, Nil, StatementList(forwardingCall :: Nil)(alias.span))(alias.span) + val aliasMethodBody = StatementList(forwardingCall :: Nil)(forwardingCall.span) + val aliasingMethodParams = + ArrayParameter("*args")(span.spanStart("*args")) :: ProcParameter("&block")(span.spanStart("&block")) :: Nil + MethodDeclaration(alias.newName, aliasingMethodParams, aliasMethodBody)( + alias.span.spanStart(s"def ${alias.newName}(*args, &block)") + ) case expr => expr } diff --git a/joern-cli/frontends/rubysrc2cpg/src/test/scala/io/joern/rubysrc2cpg/querying/MethodTests.scala b/joern-cli/frontends/rubysrc2cpg/src/test/scala/io/joern/rubysrc2cpg/querying/MethodTests.scala index a906ebfec568..fd3703f40f8b 100644 --- a/joern-cli/frontends/rubysrc2cpg/src/test/scala/io/joern/rubysrc2cpg/querying/MethodTests.scala +++ b/joern-cli/frontends/rubysrc2cpg/src/test/scala/io/joern/rubysrc2cpg/querying/MethodTests.scala @@ -323,18 +323,23 @@ class MethodTests extends RubyCode2CpgFixture { x.name shouldBe "x" bar.name shouldBe "bar=" - xeq.parameter.name.l shouldBe bar.parameter.name.l + bar.parameter.name.l shouldBe List("self", "*args", "&block") // bar forwards parameters to a call to the aliased method inside(bar.call.name("x=").l) { case barCall :: Nil => inside(barCall.argument.l) { - case _ :: (z: Identifier) :: Nil => - z.name shouldBe "z" - z.argumentIndex shouldBe 1 + case _ :: (args: Call) :: (blockId: Identifier) :: Nil => + args.name shouldBe RubyOperators.splat + args.code shouldBe "*args" + args.argumentIndex shouldBe 1 + + blockId.name shouldBe "&block" + blockId.code shouldBe "&block" + blockId.argumentIndex shouldBe 2 case xs => fail(s"Expected a two arguments for the call `x=`, instead got [${xs.code.mkString(",")}]") } - barCall.code shouldBe "x=(z)" + barCall.code shouldBe "x=(*args, &block)" case xs => fail(s"Expected a single call to `bar=`, instead got [${xs.code.mkString(",")}]") } case xs => fail(s"Expected a three virtual methods under `Foo`, instead got [${xs.code.mkString(",")}]")