From dd00f3234157d13c841c1ce783c03c6f8248f754 Mon Sep 17 00:00:00 2001 From: Pandurang Patil Date: Mon, 2 Oct 2023 12:42:33 +0530 Subject: [PATCH] [gosrc2cpg] - Handling for package level global variable access (#3703) 1. Handled package level global variable access with FieldAccess `CALL` node with respective handling to set the TypeFullName properly. 2. Made changes to handle the situation where we couldn't identify the TypeFullName in that situation, we are setting the TypeFullName of the receiver with respective labels postfixed to it like `` or ``. 3. Updated respective unit tests along with a few more unit tests. TODO: Need to handle Global Variable Declaration. Fixes #3695 --- .../gosrc2cpg/astcreation/AstCreator.scala | 2 +- .../AstForGenDeclarationCreator.scala | 29 ++- .../AstForMethodCallExpressionCreator.scala | 5 +- .../astcreation/AstForTypeDeclCreator.scala | 39 +++- .../gosrc2cpg/astcreation/CacheBuilder.scala | 27 ++- .../joern/gosrc2cpg/astcreation/Defines.scala | 2 + .../gosrc2cpg/datastructures/GoGlobal.scala | 24 ++- .../passes/ast/DownloadDependencyTest.scala | 36 +++- .../ast/GlobalVariableAndConstantTests.scala | 190 ++++++++++++++++++ .../passes/ast/TypeDeclMethodCallTests.scala | 8 +- .../testfixtures/GoCodeToCpgSuite.scala | 4 +- 11 files changed, 340 insertions(+), 26 deletions(-) create mode 100644 joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/GlobalVariableAndConstantTests.scala diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstCreator.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstCreator.scala index 418542204455..1c4f9fbebd30 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstCreator.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstCreator.scala @@ -49,7 +49,7 @@ class AstCreator(val relPathFileName: String, val parserResult: ParserResult, go private def astForTranslationUnit(rootNode: ParserNodeInfo): Ast = { val namespaceBlock = NewNamespaceBlock() .name(fullyQualifiedPackage) - .fullName(s"$relPathFileName:${fullyQualifiedPackage}") + .fullName(s"$relPathFileName:$fullyQualifiedPackage") .filename(relPathFileName) methodAstParentStack.push(namespaceBlock) val rootAst = Ast(namespaceBlock).withChild( diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForGenDeclarationCreator.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForGenDeclarationCreator.scala index a57515979470..603e3690aa24 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForGenDeclarationCreator.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForGenDeclarationCreator.scala @@ -1,5 +1,6 @@ package io.joern.gosrc2cpg.astcreation +import io.joern.gosrc2cpg.datastructures.GoGlobal import io.joern.gosrc2cpg.parser.ParserAst.* import io.joern.gosrc2cpg.parser.{ParserKeys, ParserNodeInfo} import io.joern.x2cpg @@ -40,11 +41,10 @@ trait AstForGenDeclarationCreator(implicit withSchemaValidation: ValidationMode) Seq(Ast(newImportNode(s"import $importedAsReplacement$importedEntity", importedEntity, importedAs, basicLit))) } - private def astForValueSpec(valueSpec: ParserNodeInfo): Seq[Ast] = { + protected def astForValueSpec(valueSpec: ParserNodeInfo, recordVar: Boolean = false): Seq[Ast] = { val typeFullName = Try(valueSpec.json(ParserKeys.Type)) match case Success(typeJson) => - val typeInfoNode = createParserNodeInfo(typeJson) - val (typeFullName, _, _, _) = processTypeInfo(typeInfoNode) + val (typeFullName, _, _, _) = processTypeInfo(createParserNodeInfo(typeJson)) Some(typeFullName) case _ => None @@ -54,7 +54,7 @@ trait AstForGenDeclarationCreator(implicit withSchemaValidation: ValidationMode) (valueSpec.json(ParserKeys.Names).arr.toList zip valueSpec.json(ParserKeys.Values).arr.toList) .map { case (lhs, rhs) => (createParserNodeInfo(lhs), createParserNodeInfo(rhs)) } .map { case (lhsParserNode, rhsParserNode) => - astForAssignmentCallNode(lhsParserNode, rhsParserNode, typeFullName, valueSpec.code) + astForAssignmentCallNode(lhsParserNode, rhsParserNode, typeFullName, valueSpec.code, recordVar) } .unzip localAsts ++: assCallAsts @@ -64,7 +64,7 @@ trait AstForGenDeclarationCreator(implicit withSchemaValidation: ValidationMode) .arr .flatMap { parserNode => val localParserNode = createParserNodeInfo(parserNode) - Seq(astForLocalNode(localParserNode, typeFullName)) ++: astForNode(localParserNode) + Seq(astForLocalNode(localParserNode, typeFullName, recordVar)) ++: astForNode(localParserNode) } .toSeq @@ -74,11 +74,12 @@ trait AstForGenDeclarationCreator(implicit withSchemaValidation: ValidationMode) lhsParserNode: ParserNodeInfo, rhsParserNode: ParserNodeInfo, typeFullName: Option[String], - code: String + code: String, + recordVar: Boolean = false ): (Ast, Ast) = { val rhsAst = astForBooleanLiteral(rhsParserNode) val rhsTypeFullName = typeFullName.getOrElse(getTypeFullNameFromAstNode(rhsAst)) - val localAst = astForLocalNode(lhsParserNode, Some(rhsTypeFullName)) + val localAst = astForLocalNode(lhsParserNode, Some(rhsTypeFullName), recordVar) val lhsAst = astForNode(lhsParserNode) val arguments = lhsAst ++: rhsAst val cNode = callNode( @@ -93,11 +94,19 @@ trait AstForGenDeclarationCreator(implicit withSchemaValidation: ValidationMode) (callAst(cNode, arguments), localAst) } - protected def astForLocalNode(localParserNode: ParserNodeInfo, typeFullName: Option[String]): Ast = { + protected def astForLocalNode( + localParserNode: ParserNodeInfo, + typeFullName: Option[String], + recordVar: Boolean = false + ): Ast = { val name = localParserNode.json(ParserKeys.Name).str if name != "_" then { - val node = localNode(localParserNode, name, localParserNode.code, typeFullName.getOrElse(Defines.anyTypeName)) - scope.addToScope(name, (node, typeFullName.getOrElse(Defines.anyTypeName))) + val typeFullNameStr = typeFullName.getOrElse(Defines.anyTypeName) + val node = localNode(localParserNode, name, localParserNode.code, typeFullNameStr) + + if recordVar then + GoGlobal.recordStructTypeMemberType(s"$fullyQualifiedPackage${Defines.dot}$name", typeFullNameStr) + else scope.addToScope(name, (node, typeFullNameStr)) Ast(node) } else { Ast() diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForMethodCallExpressionCreator.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForMethodCallExpressionCreator.scala index 141a107c6550..86c7b5a7e3dc 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForMethodCallExpressionCreator.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForMethodCallExpressionCreator.scala @@ -138,7 +138,10 @@ trait AstForMethodCallExpressionCreator(implicit withSchemaValidation: Validatio val callMethodFullName = s"$receiverTypeFullName.$methodName" val (returnTypeFullNameCache, signatureCache) = GoGlobal.methodFullNameReturnTypeMap - .getOrDefault(callMethodFullName, (Defines.anyTypeName, s"$callMethodFullName()")) + .getOrDefault( + callMethodFullName, + (s"$receiverTypeFullName.$methodName.${Defines.ReturnType}.${XDefines.Unknown}", s"$callMethodFullName()") + ) (methodName, signatureCache, callMethodFullName, returnTypeFullNameCache, receiverAst) } } diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForTypeDeclCreator.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForTypeDeclCreator.scala index ddd9521f4aaf..26d6c8746388 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForTypeDeclCreator.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/AstForTypeDeclCreator.scala @@ -42,14 +42,43 @@ trait AstForTypeDeclCreator(implicit withSchemaValidation: ValidationMode) { thi case _ => Seq.empty } - protected def astForFieldAccess(info: ParserNodeInfo): Seq[Ast] = { - val identifierAsts = astForNode(info.json(ParserKeys.X)) + private def processReceiver(info: ParserNodeInfo): (Seq[Ast], String) = { + val xnode = createParserNodeInfo(info.json(ParserKeys.X)) + val fieldIdentifier = info.json(ParserKeys.Sel)(ParserKeys.Name).str + xnode.node match + case Ident => + Try(xnode.json(ParserKeys.Obj)) match + case Success(_) => + // The presence of "Obj" field indicates its variable identifier and not an alias + receiverAstAndFullName(xnode, fieldIdentifier) + case _ => + // Otherwise its an alias to imported namespace using which global variable is getting accessed + val alias = xnode.json(ParserKeys.Name).str + val receiverFullName = resolveAliasToFullName(alias, fieldIdentifier) + ( + astForNode(xnode), + GoGlobal.structTypeMemberTypeMapping.getOrDefault( + receiverFullName, + s"$receiverFullName${Defines.dot}${Defines.FieldAccess}${Defines.dot}${XDefines.Unknown}" + ) + ) + case _ => + // This will take care of chained calls + receiverAstAndFullName(xnode, fieldIdentifier) + } + + private def receiverAstAndFullName(xnode: ParserNodeInfo, fieldIdentifier: String): (Seq[Ast], String) = { + val identifierAsts = astForNode(xnode) val receiverTypeFullName = getTypeFullNameFromAstNode(identifierAsts) - val fieldIdentifier = info.json(ParserKeys.Sel)(ParserKeys.Name).str val fieldTypeFullName = GoGlobal.structTypeMemberTypeMapping.getOrDefault( - receiverTypeFullName + Defines.dot + fieldIdentifier, - XDefines.Unknown + s"$receiverTypeFullName${Defines.dot}$fieldIdentifier", + s"$receiverTypeFullName${Defines.dot}$fieldIdentifier${Defines.dot}${Defines.FieldAccess}${Defines.dot}${XDefines.Unknown}" ) + (identifierAsts, fieldTypeFullName) + } + protected def astForFieldAccess(info: ParserNodeInfo): Seq[Ast] = { + val (identifierAsts, fieldTypeFullName) = processReceiver(info) + val fieldIdentifier = info.json(ParserKeys.Sel)(ParserKeys.Name).str val fieldIdentifierNode = NewFieldIdentifier() .canonicalName(fieldIdentifier) .lineNumber(line(info)) diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/CacheBuilder.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/CacheBuilder.scala index d9475576a351..6bb65ede4306 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/CacheBuilder.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/CacheBuilder.scala @@ -1,6 +1,7 @@ package io.joern.gosrc2cpg.astcreation import io.joern.gosrc2cpg.datastructures.GoGlobal +import io.joern.gosrc2cpg.parser.ParserAst.{GenDecl, ValueSpec} import io.joern.gosrc2cpg.parser.{ParserKeys, ParserNodeInfo} import io.joern.x2cpg.Ast import ujson.{Arr, Obj, Value} @@ -11,16 +12,40 @@ trait CacheBuilder { this: AstCreator => def buildCache(): Unit = { try { - findAndProcess(parserResult.json) // Declared package name and namespace ending folder token is not matching then cache the alias to namespace mapping if (!fullyQualifiedPackage.endsWith(declaredPackageName)) { GoGlobal.recordAliasToNamespaceMapping(declaredPackageName, fullyQualifiedPackage) } + findAndProcess(parserResult.json) + processPackageLevelGolbalVaraiblesAndConstants(parserResult.json) } catch case ex: Exception => logger.warn(s"Error: While processing - ${parserResult.fullPath}", ex) } + private def processPackageLevelGolbalVaraiblesAndConstants(json: Value): Unit = { + json(ParserKeys.Decls).arrOpt + .getOrElse(List()) + .map(createParserNodeInfo) + .foreach(decl => { + decl.node match + case GenDecl => + decl + .json(ParserKeys.Specs) + .arrOpt + .getOrElse(List()) + .map(createParserNodeInfo) + .foreach(spec => { + spec.node match + case ValueSpec => astForValueSpec(spec, true) + case _ => + // Only process ValueSpec + }) + case _ => + // Only process GenDecl + }) + } + private def findAndProcess(json: Value): Unit = { json match { case obj: Obj => diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/Defines.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/Defines.scala index 3f3f4271221e..9b323a45ac6a 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/Defines.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/astcreation/Defines.scala @@ -10,6 +10,8 @@ object Defines { val chan = "chan" val This: String = "this" val Bool = "bool" + val FieldAccess = "" + val ReturnType = "" val primitiveTypeMap: Map[String, String] = // This list is prepared with reference to primitives defined at https://pkg.go.dev/builtin#pkg-types diff --git a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/datastructures/GoGlobal.scala b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/datastructures/GoGlobal.scala index 2c212a6f34b9..d0f98ce25770 100644 --- a/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/datastructures/GoGlobal.scala +++ b/joern-cli/frontends/gosrc2cpg/src/main/scala/io/joern/gosrc2cpg/datastructures/GoGlobal.scala @@ -22,9 +22,29 @@ object GoGlobal extends Global { * * In above sample as the package name `fpkg` is different from `lib` this one will be cached in the map */ - val aliasToNameSpaceMapping: ConcurrentHashMap[String, String] = new ConcurrentHashMap() + val aliasToNameSpaceMapping: ConcurrentHashMap[String, String] = new ConcurrentHashMap() + + // Mapping method fullname to its return type and signature val methodFullNameReturnTypeMap: ConcurrentHashMap[String, (String, String)] = new ConcurrentHashMap() - val structTypeMemberTypeMapping: ConcurrentHashMap[String, String] = new ConcurrentHashMap() + + /** Mapping fully qualified name of the member variable of a struct type to it's type It will also maintain the type + * mapping for package level global variables. e.g. + * + * module namespace = joern.io/sample + * + * package sample + * + * type Person struct{ Age int} + * + * var ( HostURL = "http://api.sample.com" ) + * + * It will map + * + * `joern.io/sample.Person.Age` - `int` + * + * `joern.io/sample.HostURL` - `string` + */ + val structTypeMemberTypeMapping: ConcurrentHashMap[String, String] = new ConcurrentHashMap() def recordAliasToNamespaceMapping(alias: String, namespace: String): Unit = { aliasToNameSpaceMapping.putIfAbsent(alias, namespace) diff --git a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/DownloadDependencyTest.scala b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/DownloadDependencyTest.scala index 5ad2816d86fb..3d1dc208e401 100644 --- a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/DownloadDependencyTest.scala +++ b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/DownloadDependencyTest.scala @@ -2,6 +2,7 @@ package io.joern.go2cpg.passes.ast import io.joern.go2cpg.testfixtures.GoCodeToCpgSuite import io.joern.gosrc2cpg.Config +import io.shiftleft.codepropertygraph.generated.Operators import io.shiftleft.semanticcpg.language.* class DownloadDependencyTest extends GoCodeToCpgSuite { @@ -18,7 +19,7 @@ class DownloadDependencyTest extends GoCodeToCpgSuite { "go.mod" ).moreCode(""" |package main - | + |import "github.com/google/uuid" |func main() { | var uud = uuid.NewString() |} @@ -30,4 +31,37 @@ class DownloadDependencyTest extends GoCodeToCpgSuite { x.typeFullName shouldBe "string" } } + + "unresolved dependency tests" should { + val cpg = code( + """ + |module joern.io/sample + |go 1.18 + |require ( + | joern.io/sampletwo v1.3.1 + |) + |""".stripMargin, + "go.mod" + ).moreCode(""" + |package main + |import "joern.io/sampletwo" + |func main() { + | var a = sampletwo.Person{Name:"Pandurang"} + | var b = a.Name + | var c = a.FullName() + | var d = a.Process().FullName() + | var e = a.Process().SomeField + |} + |""".stripMargin) + + "Be correct for CALL Node typeFullNames" in { + val List(a, b, c, d, e, f, g) = cpg.call.nameNot(Operators.assignment).l + a.typeFullName shouldBe "joern.io/sampletwo.Person" + b.typeFullName shouldBe "joern.io/sampletwo.Person.Name.." + c.typeFullName shouldBe "joern.io/sampletwo.Person.FullName.." + d.typeFullName shouldBe "joern.io/sampletwo.Person.Process...FullName.." + e.typeFullName shouldBe "joern.io/sampletwo.Person.Process.." + f.typeFullName shouldBe "joern.io/sampletwo.Person.Process...SomeField.." + } + } } diff --git a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/GlobalVariableAndConstantTests.scala b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/GlobalVariableAndConstantTests.scala new file mode 100644 index 000000000000..33d3ce4bfd96 --- /dev/null +++ b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/GlobalVariableAndConstantTests.scala @@ -0,0 +1,190 @@ +package io.joern.go2cpg.passes.ast + +import io.joern.go2cpg.testfixtures.GoCodeToCpgSuite +import io.shiftleft.codepropertygraph.generated.Operators +import io.shiftleft.semanticcpg.language.* + +import java.io.File + +class GlobalVariableAndConstantTests extends GoCodeToCpgSuite { + + "Global variable declaration check" should { + val cpg = code(""" + |package main + |const ( + | FooConst = "Test" + |) + |var ( + | BarVar = 100 + |) + |func main() { + | println(FooConst) + |} + |""".stripMargin) + + "Check LOCAL node" in { + val List(a, b) = cpg.local.l + a.typeFullName shouldBe "string" + b.typeFullName shouldBe "int" + } + } + + "Var defined(with type mentioned) in one package used in another package" should { + val cpg = code( + """ + |module joern.io/sample + |go 1.18 + |""".stripMargin, + "go.mod" + ).moreCode( + """ + |package lib1 + | + |var( + | SchemeHTTP string = "http" + |) + | + |""".stripMargin, + Seq("lib1", "typelib.go").mkString(File.separator) + ).moreCode( + """ + |package main + |import "joern.io/sample/lib1" + |func main() { + | var a = lib1.SchemeHTTP.value() + |} + |""".stripMargin, + "main.go" + ) + + "Be correct for Field Access CALL Node for Global variable access" in { + val List(x) = cpg.call(Operators.fieldAccess).l + x.typeFullName shouldBe "string" + } + + "Check methodfullname of variable imported from other package " in { + val List(callNode) = cpg.call("value").l + callNode.methodFullName shouldBe "string.value" + } + } + + "Var defined(without type mentioned) in one package used in another package" should { + val cpg = code( + """ + |module joern.io/sample + |go 1.18 + |""".stripMargin, + "go.mod" + ).moreCode( + """ + |package lib1 + | + |var( + | SchemeHTTP = "http" + |) + | + |""".stripMargin, + Seq("lib1", "typelib.go").mkString(File.separator) + ).moreCode( + """ + |package main + |import "joern.io/sample/lib1" + |func main() { + | var a = lib1.SchemeHTTP.value() + |} + |""".stripMargin, + "main.go" + ) + + "Be correct for Field Access CALL Node for Global variable access" in { + val List(x) = cpg.call(Operators.fieldAccess).l + x.typeFullName shouldBe "string" + } + + "Check methodfullname of variable imported from other package " in { + val List(callNode) = cpg.call("value").l + callNode.methodFullName shouldBe "string.value" + } + } + "Const defined(with type mentioned) in one package used in another package" should { + val cpg = code( + """ + |module joern.io/sample + |go 1.18 + |""".stripMargin, + "go.mod" + ).moreCode( + """ + |package lib1 + | + |const ( + | SchemeHTTP string = "http" + |) + | + |""".stripMargin, + Seq("lib1", "typelib.go").mkString(File.separator) + ).moreCode( + """ + |package main + |import "joern.io/sample/lib1" + |func main() { + | var a = lib1.SchemeHTTP.value() + |} + |""".stripMargin, + "main.go" + ) + + "Be correct for Field Access CALL Node for Global variable access" in { + val List(x) = cpg.call(Operators.fieldAccess).l + x.typeFullName shouldBe "string" + } + + "Check methodfullname of constant imported from other package " in { + val List(callNode) = cpg.call("value").l + callNode.methodFullName shouldBe "string.value" + } + } + + "const defined(without type mentioned) in one package used in another package" should { + val cpg = code( + """ + |module joern.io/sample + |go 1.18 + |""".stripMargin, + "go.mod" + ).moreCode( + """ + |package lib1 + | + |const ( + | SchemeHTTP = "http" + |) + | + |""".stripMargin, + Seq("lib1", "typelib.go").mkString(File.separator) + ).moreCode( + """ + |package main + |import "joern.io/sample/lib1" + |import "joern.io/sample/lib2" + |func main() { + | var a = lib1.SchemeHTTP.value() + | var b = lib2.SchemeHTTP.value() + |} + |""".stripMargin, + "main.go" + ) + + "Be correct for Field Access CALL Node for Global variable access" in { + val List(a, b) = cpg.call(Operators.fieldAccess).l + a.typeFullName shouldBe "string" + b.typeFullName shouldBe "joern.io/sample/lib2.SchemeHTTP.." + } + + "Check methodfullname of constant imported from other package " in { + val List(callNode, callNode2) = cpg.call("value").l + callNode.methodFullName shouldBe "string.value" + callNode2.methodFullName shouldBe "joern.io/sample/lib2.SchemeHTTP...value" + } + } +} diff --git a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/TypeDeclMethodCallTests.scala b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/TypeDeclMethodCallTests.scala index 532179a17661..41838f73a829 100644 --- a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/TypeDeclMethodCallTests.scala +++ b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/passes/ast/TypeDeclMethodCallTests.scala @@ -213,10 +213,10 @@ class TypeDeclMethodCallTests extends GoCodeToCpgSuite { cpg.call("bar").size shouldBe 1 val List(x) = cpg.call("bar").l x.code shouldBe "ctx.data.bar(a)" - x.methodFullName shouldBe ".bar" + x.methodFullName shouldBe "main.context.data...bar" x.order shouldBe 2 x.lineNumber shouldBe Option(7) - x.typeFullName shouldBe Defines.anyTypeName + x.typeFullName shouldBe "main.context.data...bar.." } "Check call node properties on five times chained" in { @@ -236,10 +236,10 @@ class TypeDeclMethodCallTests extends GoCodeToCpgSuite { cpg.call("bar").size shouldBe 1 val List(x) = cpg.call("bar").l x.code shouldBe "ctx.data1.data2.data3.data4.bar(a)" - x.methodFullName shouldBe ".bar" + x.methodFullName shouldBe "main.context.data1...data2...data3...data4...bar" x.order shouldBe 2 x.lineNumber shouldBe Option(7) - x.typeFullName shouldBe Defines.anyTypeName + x.typeFullName shouldBe "main.context.data1...data2...data3...data4...bar.." } } diff --git a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/testfixtures/GoCodeToCpgSuite.scala b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/testfixtures/GoCodeToCpgSuite.scala index a6bd0aa7498e..92e226eb49b3 100644 --- a/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/testfixtures/GoCodeToCpgSuite.scala +++ b/joern-cli/frontends/gosrc2cpg/src/test/scala/io/joern/go2cpg/testfixtures/GoCodeToCpgSuite.scala @@ -17,7 +17,7 @@ trait Go2CpgFrontend extends LanguageFrontend { cpgOutFile.deleteOnExit() val go2cpg = new GoSrc2Cpg() val config = getConfig() - .map(_.asInstanceOf[Config]) + .collectFirst { case x: Config => x } .getOrElse(Config()) .withInputPath(sourceCodePath.getAbsolutePath) .withOutputPath(cpgOutFile.pathAsString) @@ -52,5 +52,7 @@ class GoCodeToCpgSuite(fileSuffix: String = ".go", withOssDataflow: Boolean = fa override def beforeEach(): Unit = { GoGlobal.methodFullNameReturnTypeMap.clear() + GoGlobal.aliasToNameSpaceMapping.clear() + GoGlobal.structTypeMemberTypeMapping.clear() } }