Skip to content

Commit

Permalink
[ruby] self Param REF Edge (#4838)
Browse files Browse the repository at this point in the history
* [ruby] `self` Param `REF` Edge
Fixed issue where no `REF` edges between self params and their identifiers.

* Fixed the rest of the cases where `self` would have no refs

* Updated test expectation
  • Loading branch information
DavidBakerEffendi authored Aug 12, 2024
1 parent e83cae3 commit 71e5e7f
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package io.joern.rubysrc2cpg.astcreation

import io.shiftleft.codepropertygraph.generated.DiffGraphBuilder
import io.joern.rubysrc2cpg.astcreation.RubyIntermediateAst.*
import io.joern.rubysrc2cpg.datastructures.{BlockScope, NamespaceScope, RubyProgramSummary, RubyScope, RubyStubbedType}
import io.joern.rubysrc2cpg.datastructures.{BlockScope, NamespaceScope, RubyProgramSummary, RubyScope}
import io.joern.rubysrc2cpg.parser.{RubyNodeCreator, RubyParser}
import io.joern.rubysrc2cpg.passes.Defines
import io.joern.x2cpg.utils.NodeBuilders.{newBindingNode, newModifierNode}
import io.joern.x2cpg.utils.NodeBuilders.{newModifierNode, newThisParameterNode}
import io.joern.x2cpg.{Ast, AstCreatorBase, AstNodeBuilder, ValidationMode}
import io.shiftleft.codepropertygraph.generated.{DispatchTypes, EdgeTypes, ModifierTypes, Operators}
import io.shiftleft.codepropertygraph.generated.{DiffGraphBuilder, ModifierTypes}
import io.shiftleft.codepropertygraph.generated.nodes.*
import io.shiftleft.semanticcpg.language.types.structure.NamespaceTraversal
import org.slf4j.{Logger, LoggerFactory}
import io.shiftleft.codepropertygraph.generated.DiffGraphBuilder

import java.util.regex.Matcher

Expand Down Expand Up @@ -97,6 +95,16 @@ class AstCreator(
signature = None,
fileName = relativeFileName
)
val thisParameterNode = newThisParameterNode(
name = Defines.Self,
code = Defines.Self,
typeFullName = Defines.Any,
line = methodNode_.lineNumber,
column = methodNode_.columnNumber,
dynamicTypeHintFullName = fullName :: Nil
)
val thisParameterAst = Ast(thisParameterNode)
scope.addToScope(Defines.Self, thisParameterNode)
val methodReturn = methodReturnNode(rootNode, Defines.Any)

scope.newProgramScope
Expand All @@ -110,7 +118,7 @@ class AstCreator(
scope.popScope()
methodAst(
methodNode_,
Seq.empty,
thisParameterAst :: Nil,
bodyAst,
methodReturn,
newModifierNode(ModifierTypes.MODULE) :: newModifierNode(ModifierTypes.VIRTUAL) :: Nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -732,8 +732,12 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {

private def astForSelfIdentifier(node: SelfIdentifier): Ast = {
val thisIdentifier =
identifierNode(node, Defines.Self, code(node), scope.surroundingTypeFullName.getOrElse(Defines.Any))
Ast(thisIdentifier)
identifierNode(node, Defines.Self, code(node), Defines.Any, scope.surroundingTypeFullName.toList)

scope
.lookupVariable(Defines.Self)
.map(selfParam => Ast(thisIdentifier).withRefEdge(thisIdentifier, selfParam))
.getOrElse(Ast(thisIdentifier))
}

protected def astForUnknown(node: RubyNode): Ast = {
Expand Down Expand Up @@ -790,7 +794,11 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {
MemberAccess(SelfIdentifier()(node.span.spanStart(Defines.Self)), ".", call.name)(node.span),
stripLeadingAt = true
)
val baseAst = Ast(identifierNode(node, Defines.Self, Defines.Self, receiverType))
val selfIdentifier = identifierNode(node, Defines.Self, Defines.Self, receiverType)
val baseAst = scope
.lookupVariable(Defines.Self)
.map(selfParam => Ast(selfIdentifier).withRefEdge(selfIdentifier, selfParam))
.getOrElse(Ast(selfIdentifier))
callAst(call, argumentAst, Option(baseAst), Option(receiverAst))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,16 @@ trait AstForFunctionsCreator(implicit withSchemaValidation: ValidationMode) { th
if (isConstructor) scope.pushNewScope(ConstructorScope(fullName))
else scope.pushNewScope(MethodScope(fullName, procParamGen.fresh))

val thisParameterAst = Ast(
newThisParameterNode(
name = Defines.Self,
code = Defines.Self,
typeFullName = scope.surroundingTypeFullName.getOrElse(Defines.Any),
line = method.lineNumber,
column = method.columnNumber
)
val thisParameterNode = newThisParameterNode(
name = Defines.Self,
code = Defines.Self,
typeFullName = Defines.Any,
line = method.lineNumber,
column = method.columnNumber,
dynamicTypeHintFullName = scope.surroundingTypeFullName.toList
)
val thisParameterAst = Ast(thisParameterNode)
scope.addToScope(Defines.Self, thisParameterNode)
val parameterAsts = thisParameterAst :: astForParameters(node.parameters)

val optionalStatementList = statementListForOptionalParams(node.parameters)
Expand Down Expand Up @@ -365,15 +366,15 @@ trait AstForFunctionsCreator(implicit withSchemaValidation: ValidationMode) { th

createMethodTypeBindings(method, methodTypeDecl_)

val thisParameterAst = Ast(
newThisParameterNode(
name = Defines.Self,
code = thisParamCode,
typeFullName = astParentFullName.getOrElse(Defines.Any),
line = method.lineNumber,
column = method.columnNumber
)
val thisNode = newThisParameterNode(
name = Defines.Self,
code = thisParamCode,
typeFullName = astParentFullName.getOrElse(Defines.Any),
line = method.lineNumber,
column = method.columnNumber
)
val thisParameterAst = Ast(thisNode)
scope.addToScope(Defines.Self, thisNode)

val parameterAsts = thisParameterAst :: astForParameters(node.parameters)
val optionalStatementList = statementListForOptionalParams(node.parameters)
Expand Down Expand Up @@ -439,7 +440,11 @@ trait AstForFunctionsCreator(implicit withSchemaValidation: ValidationMode) { th
.methodFullName(Operators.fieldAccess)
.dispatchType(DispatchTypes.STATIC_DISPATCH)
.typeFullName(Defines.Any)
callAst(fieldAccess, Seq(Ast(self), Ast(fi)))
val selfAst = scope
.lookupVariable(Defines.Self)
.map(selfParam => Ast(self).withRefEdge(self, selfParam))
.getOrElse(Ast(self))
callAst(fieldAccess, Seq(selfAst, Ast(fi)))
}

astForAssignment(methodRefIdent, methodRefNode, method.lineNumber, method.columnNumber)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,11 @@ trait AstForTypesCreator(implicit withSchemaValidation: ValidationMode) { this:
.methodFullName(Operators.fieldAccess)
.dispatchType(DispatchTypes.STATIC_DISPATCH)
.typeFullName(Defines.Any)
callAst(fieldAccess, Seq(Ast(self), Ast(fi)))
val selfAst = scope
.lookupVariable(Defines.Self)
.map(selfParam => Ast(self).withRefEdge(self, selfParam))
.getOrElse(Ast(self))
callAst(fieldAccess, Seq(selfAst, Ast(fi)))
}
astForAssignment(typeRefIdent, typeRefNode, typeDecl.lineNumber, typeDecl.columnNumber)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.shiftleft.codepropertygraph.generated.nodes.{Call, FieldIdentifier, Id
import io.shiftleft.codepropertygraph.generated.{DispatchTypes, Operators}
import io.shiftleft.semanticcpg.language.*
import io.joern.rubysrc2cpg.passes.Defines.Main
import io.joern.rubysrc2cpg.passes.Defines

class FieldAccessTests extends RubyCode2CpgFixture {

Expand Down Expand Up @@ -50,7 +51,8 @@ class FieldAccessTests extends RubyCode2CpgFixture {
case (self: Identifier) :: (sickDaysId: FieldIdentifier) :: Nil =>
self.name shouldBe "self"
self.code shouldBe "self"
self.typeFullName should endWith("PaidTimeOff")
self.typeFullName shouldBe Defines.Any
self.dynamicTypeHintFullName.head should endWith("PaidTimeOff")

sickDaysId.canonicalName shouldBe "@sick_days_earned"
sickDaysId.code shouldBe "sick_days_earned"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class MethodTests extends RubyCode2CpgFixture {
"`def f(x) = 1`" should {
val cpg = code("""
|def f(x) = 1
|f(1)
|""".stripMargin)

"be represented by a METHOD node" in {
Expand All @@ -27,6 +28,18 @@ class MethodTests extends RubyCode2CpgFixture {
x.index shouldBe 1
x.isVariadic shouldBe false
x.lineNumber shouldBe Some(2)

val List(fSelf) = f.parameter.name(RDefines.Self).l
fSelf.index shouldBe 0
fSelf.isVariadic shouldBe false
fSelf.lineNumber shouldBe Some(2)
fSelf.referencingIdentifiers.size shouldBe 0

val List(mSelf) = cpg.method.isModule.parameter.name(RDefines.Self).l
mSelf.index shouldBe 0
mSelf.isVariadic shouldBe false
mSelf.lineNumber shouldBe Some(1)
mSelf.referencingIdentifiers.size shouldBe 3
}

"have a corresponding bound type" in {
Expand Down

0 comments on commit 71e5e7f

Please sign in to comment.