Skip to content

Commit

Permalink
[gosrc2cpg] - pending items for method node (#3543)
Browse files Browse the repository at this point in the history
  • Loading branch information
pandurangpatil authored Aug 29, 2023
1 parent b694594 commit 40b6c39
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
gosrc2cpg {
goastgen_version: "0.6.1"
goastgen_version: "0.9.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ trait AstCreatorHelper { this: AstCreator =>
val node = nodeType(json)
val pni = ParserNodeInfo(node, json, c, ln, cn, lnEnd, cnEnd)
parserNodeCache.addOne(json(ParserKeys.NodeId).num.toLong, pni)
node match
case CallExpr =>
json(ParserKeys.Fun)(ParserKeys.Obj).objOpt.map(obj => {
createParserNodeInfo(obj(ParserKeys.Decl))
})
case _ =>
// Do nothing
pni
case Success(nodeReferenceId) => parserNodeCache(nodeReferenceId)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ trait AstForFunctionsCreator(implicit withSchemaValidation: ValidationMode) { th
): Ast = {

val parentNode: NewTypeDecl = methodAstParentStack.collectFirst { case t: NewTypeDecl => t }.getOrElse {
// TODO: Need to add respective Unit test to test this possibility, as looks to me as dead code. Replicated it from 'c2cpg' by referring AstForFunctionsCreator.
// TODO: Need to add respective Unit test to test this possibility, as looks to me as dead code.
// Replicated it from 'c2cpg' by referring AstForFunctionsCreator.
val astParentType = methodAstParentStack.head.label
val astParentFullName = methodAstParentStack.head.properties(PropertyNames.FULL_NAME).toString
val typeDeclNode_ =
Expand All @@ -45,7 +46,7 @@ trait AstForFunctionsCreator(implicit withSchemaValidation: ValidationMode) { th
// TODO: handle multiple return type or tuple (int, int)
val returnType = getReturnType(funcDecl.json(ParserKeys.Type)).headOption.getOrElse("")
val templateParams = ""
val params = createParserNodeInfo(funcDecl.json(ParserKeys.Type)(ParserKeys.Params))
val params = funcDecl.json(ParserKeys.Type)(ParserKeys.Params)(ParserKeys.List)
val signature =
s"$fullname$templateParams (${parameterSignature(params)})$returnType"

Expand All @@ -64,17 +65,15 @@ trait AstForFunctionsCreator(implicit withSchemaValidation: ValidationMode) { th
Seq(astForMethod.merge(typeDeclAst))
}

private def astForMethodParameter(params: ParserNodeInfo): Seq[Ast] = {
private def astForMethodParameter(params: Value): Seq[Ast] = {
var index = 1
params
.json(ParserKeys.List)
.arrOpt
.getOrElse(ArrayBuffer())
params.arrOpt
.getOrElse(List())
.flatMap(x =>
val typeInfo = createParserNodeInfo(x(ParserKeys.Type))
val (typeFullName, typeFullNameForcode, isVariadic, evaluationStrategy) = processTypeInfo(typeInfo.json)
x(ParserKeys.Names).arrOpt
.getOrElse(ArrayBuffer())
.getOrElse(List())
.map(y => {
// We are returning same type from x object for each name in the names array.
val parameterInfo = createParserNodeInfo(y)
Expand All @@ -89,24 +88,23 @@ trait AstForFunctionsCreator(implicit withSchemaValidation: ValidationMode) { th
typeFullName
)
index += 1
scope.addToScope(paramName, (parameterNode, typeFullName))
Ast(parameterNode)
})
)
.toSeq
}

private def parameterSignature(params: ParserNodeInfo): String = {
private def parameterSignature(params: Value): String = {
// func foo(argc, something int, argv string) int {
// We get params -> list -> names [argc, something], type (int)
params
.json(ParserKeys.List)
.arrOpt
params.arrOpt
.getOrElse(ArrayBuffer())
.map(x =>
val typeInfo = createParserNodeInfo(x(ParserKeys.Type))
val (typeFullName, typeFullNameForcode, isVariadic, _) = processTypeInfo(typeInfo.json)
x(ParserKeys.Names).arrOpt
.getOrElse(ArrayBuffer())
.getOrElse(List())
.map(_ => {
// We are returning same type from x object for each name in the names array.
typeFullName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,6 @@ object ParserKeys {
val Elt = "Elt"
val Sel = "Sel"
val Elts = "Elts"
val Fun = "Fun"
val Fields = "Fields"
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,51 @@ class MethodTests extends GoCodeToCpgSuite {
}
}

"Method called from another method first in the code" should {
val cpg = code("""
|package main
|func foo() {
| bar()
|}
|func bar() {
|}
|""".stripMargin)

"Be correct with method node properties" in {
val List(x) = cpg.method.name("foo").l
x.name shouldBe "foo"
x.fullName shouldBe "main.foo"
x.code should startWith("func foo() {")
x.signature shouldBe "main.foo ()"
x.isExternal shouldBe false
x.astParentType shouldBe NodeTypes.TYPE_DECL
x.astParentFullName shouldBe "Test0.go:main.<global>"
x.order shouldBe 1
x.filename shouldBe "Test0.go"
x.lineNumber shouldBe Option(3)
x.lineNumberEnd shouldBe Option(5)

val List(y) = cpg.method.name("bar").l
y.name shouldBe "bar"
y.fullName shouldBe "main.bar"
y.code should startWith("func bar() {")
y.signature shouldBe "main.bar ()"
y.isExternal shouldBe false
y.astParentType shouldBe NodeTypes.TYPE_DECL
y.astParentFullName shouldBe "Test0.go:main.<global>"
y.order shouldBe 2
y.filename shouldBe "Test0.go"
y.lineNumber shouldBe Option(6)
y.lineNumberEnd shouldBe Option(7)
}

"check binding Node" in {
val List(x) = cpg.method.name("foo").bindingTypeDecl.l
x.name shouldBe "main.<global>"
x.fullName shouldBe "Test0.go:main.<global>"
}
}

"Method arguments with primitive types" should {
val cpg = code("""
|package main
Expand Down Expand Up @@ -317,6 +362,59 @@ class MethodTests extends GoCodeToCpgSuite {
}
}

"Method arguments with primitive pointer to pointer" should {
val cpg = code("""
|package main
|func foo(argc int, argv **string) {
|}
|""".stripMargin)

"Be correct with method node properties" ignore {
val List(x) = cpg.method.name("foo").l
x.name shouldBe "foo"
x.fullName shouldBe "main.foo"
x.code should startWith("func foo(argc int, argv **string)")
// TODO: pointer to pointer use cae need to be hanled
x.signature shouldBe "main.foo (int, **string)"
x.isExternal shouldBe false
x.astParentType shouldBe NodeTypes.TYPE_DECL
x.astParentFullName shouldBe "Test0.go:main.<global>"
x.order shouldBe 1
x.filename shouldBe "Test0.go"
x.lineNumber shouldBe Option(3)
x.lineNumberEnd shouldBe Option(4)
}

"be correct for parameter nodes" ignore {
cpg.parameter.name.l shouldBe List("argc", "argv")
val List(argc) = cpg.parameter.name("argc").l
argc.code shouldBe "argc int"
argc.order shouldBe 1
argc.typeFullName shouldBe "int"
argc.isVariadic shouldBe false
argc.evaluationStrategy shouldBe EvaluationStrategies.BY_VALUE

val List(argv) = cpg.parameter.name("argv").l
argv.code shouldBe "argv **string"
argv.order shouldBe 2
// TODO: pointer to pointer use cae need to be hanled
argv.typeFullName shouldBe "**string"
argv.isVariadic shouldBe false
argv.evaluationStrategy shouldBe EvaluationStrategies.BY_SHARING
}

"traversing from parameter to method" in {
cpg.parameter.name("argc").method.name.l shouldBe List("foo")
cpg.parameter.name("argv").method.name.l shouldBe List("foo")
}

"traversing from method to parameter" in {
val List(argc, argv) = cpg.method.name("foo").parameter.l
argc.name shouldBe "argc"
argv.name shouldBe "argv"
}
}

"Method arguments with array of primitive pointer" should {
val cpg = code("""
|package main
Expand Down Expand Up @@ -1239,7 +1337,70 @@ class MethodTests extends GoCodeToCpgSuite {
argd.name shouldBe "argd"
}
}
// TODO: Add pointer to pointer use case.

"struct type argument from third party dependency imported as . " should {
val cpg = code(
"""
|module joern.io/sample
|go 1.18
|""".stripMargin,
"go.mod"
).moreCode(
"""
|package main
|import . "privado.ai/test/fpkg"
|func foo(argc int, argv Sample) {
|}
|""".stripMargin,
"main.go"
)

"Be correct with method node properties" ignore {
val List(x) = cpg.method.name("foo").l
x.name shouldBe "foo"
x.fullName shouldBe "main.foo"
x.code should startWith("func foo(argc int, argv Sample)")
// TODO: wrong methodfull name being genearted when the packaged is imported with '.'
x.signature shouldBe "main.foo (int, privado.ai/test/fpkg.Sample)"
x.isExternal shouldBe false
x.astParentType shouldBe NodeTypes.TYPE_DECL
x.astParentFullName shouldBe "main.go:main.<global>"
x.order shouldBe 2
x.filename shouldBe "main.go"
x.lineNumber shouldBe Option(4)
x.lineNumberEnd shouldBe Option(5)
}

"be correct for parameter nodes" ignore {
cpg.parameter.name.l shouldBe List("argc", "argv")
val List(argc) = cpg.parameter.name("argc").l
argc.code shouldBe "argc int"
argc.order shouldBe 1
argc.typeFullName shouldBe "int"
argc.isVariadic shouldBe false
argc.evaluationStrategy shouldBe EvaluationStrategies.BY_VALUE

val List(argv) = cpg.parameter.name("argv").l
argv.code shouldBe "argv Sample"
argv.order shouldBe 2
// TODO: wrong methodfull name being genearted when the packaged is imported with '.'
argv.typeFullName shouldBe "privado.ai/test/fpkg.Sample"
argv.isVariadic shouldBe false
argv.evaluationStrategy shouldBe EvaluationStrategies.BY_VALUE
}

"traversing from parameter to method" in {
cpg.parameter.name("argc").method.name.l shouldBe List("foo")
cpg.parameter.name("argv").method.name.l shouldBe List("foo")
}

"traversing from method to parameter" in {
val List(argc, argv) = cpg.method.name("foo").parameter.l
argc.name shouldBe "argc"
argv.name shouldBe "argv"
}
}

// TODO: Add unit test for tuple return
// TODO: Add unit tests with Generics
}

0 comments on commit 40b6c39

Please sign in to comment.