diff --git a/build.sbt b/build.sbt index bdb22e58ab04..8efa6ea389c2 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ name := "joern" ThisBuild / organization := "io.joern" ThisBuild / scalaVersion := "3.3.1" -val cpgVersion = "1.4.23" +val cpgVersion = "1.4.24" lazy val joerncli = Projects.joerncli lazy val querydb = Projects.querydb @@ -64,7 +64,7 @@ ThisBuild / compile / javacOptions ++= Seq( ThisBuild / scalacOptions ++= Seq( "-deprecation", // Emit warning and location for usages of deprecated APIs. "--release", - "11", + "11" ) lazy val createDistribution = taskKey[File]("Create a complete Joern distribution") diff --git a/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/passes/base/AstLinkerPass.scala b/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/passes/base/AstLinkerPass.scala index db1d38197239..5fd666d2fa43 100644 --- a/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/passes/base/AstLinkerPass.scala +++ b/joern-cli/frontends/x2cpg/src/main/scala/io/joern/x2cpg/passes/base/AstLinkerPass.scala @@ -5,7 +5,7 @@ import io.shiftleft.codepropertygraph.Cpg import io.shiftleft.codepropertygraph.generated.nodes.StoredNode import io.shiftleft.codepropertygraph.generated.{EdgeTypes, NodeTypes} import io.shiftleft.passes.CpgPass -import io.shiftleft.semanticcpg.language._ +import io.shiftleft.semanticcpg.language.* class AstLinkerPass(cpg: Cpg) extends CpgPass(cpg) with LinkingUtil { @@ -16,6 +16,15 @@ class AstLinkerPass(cpg: Cpg) extends CpgPass(cpg) with LinkingUtil { cpg.typeDecl.whereNot(_.astParent).foreach { typeDecl => addAstParent(typeDecl, typeDecl.fullName, typeDecl.astParentType, typeDecl.astParentFullName, dstGraph) } + cpg.member.whereNot(_.astParent).foreach { member => + addAstParent( + member, + s"${member.astParentFullName}.${member.name}", + member.astParentType, + member.astParentFullName, + dstGraph + ) + } } /** For the given method or type declaration, determine its parent in the AST via the AST_PARENT_TYPE and diff --git a/joern-cli/frontends/x2cpg/src/test/scala/io/joern/x2cpg/passes/AstLinkerPassTest.scala b/joern-cli/frontends/x2cpg/src/test/scala/io/joern/x2cpg/passes/AstLinkerPassTest.scala new file mode 100644 index 000000000000..148b5e9c224f --- /dev/null +++ b/joern-cli/frontends/x2cpg/src/test/scala/io/joern/x2cpg/passes/AstLinkerPassTest.scala @@ -0,0 +1,36 @@ +package io.joern.x2cpg.passes + +import io.joern.x2cpg.layers.Base +import io.joern.x2cpg.passes.base.AstLinkerPass +import io.joern.x2cpg.{Ast, ValidationMode} +import io.shiftleft.codepropertygraph.generated.* +import io.shiftleft.codepropertygraph.generated.nodes.{NewCall, NewMember, NewTypeDecl} +import io.shiftleft.semanticcpg.language.* +import io.shiftleft.semanticcpg.layers.LayerCreatorContext +import io.shiftleft.semanticcpg.testing.MockCpg +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + +class AstLinkerPassTest extends AnyWordSpec with Matchers { + + "Check member node is child of TypeDecl node" in { + val cpg = MockCpg().withCustom { (graph, _) => + implicit val withSchemaValidation: ValidationMode = ValidationMode.Disabled + val typeDecl = NewTypeDecl().name("Sample").fullName("namespace.Sample") + Ast.storeInDiffGraph(Ast(typeDecl), graph) + val memberNode = NewMember() + .name("test") + .typeFullName("String") + .astParentType(NodeTypes.TYPE_DECL) + .astParentFullName("namespace.Sample") + Ast.storeInDiffGraph(Ast(memberNode), graph) + }.cpg + + val context = new LayerCreatorContext(cpg) + new Base().run(context) + val List(typeDecl) = cpg.typeDecl("Sample").l + val List(member) = typeDecl.member.l + member.typeFullName shouldBe "String" + member.name shouldBe "test" + } +}