Skip to content

Commit

Permalink
[javasrc2cpg] Fix orphan outerClass locals in constructor bodies (#5220)
Browse files Browse the repository at this point in the history
* Fix orphan local class identifiers
  • Loading branch information
johannescoetzee authored Jan 16, 2025
1 parent c5c8ef5 commit f83f225
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.joern.javasrc2cpg

import io.joern.javasrc2cpg.passes.{AstCreationPass, TypeInferencePass}
import io.joern.javasrc2cpg.passes.{AstCreationPass, OuterClassRefPass, TypeInferencePass}
import io.joern.x2cpg.X2Cpg.withNewEmptyCpg
import io.joern.x2cpg.passes.frontend.{JavaConfigFileCreationPass, MetaDataPass, TypeNodePass}
import io.joern.x2cpg.X2CpgFrontend
Expand All @@ -22,6 +22,7 @@ class JavaSrc2Cpg extends X2CpgFrontend[Config] {
astCreationPass.createAndApply()
astCreationPass.sourceParser.cleanupDelombokOutput()
astCreationPass.clearJavaParserCaches()
new OuterClassRefPass(cpg).createAndApply()
JavaConfigFileCreationPass(cpg).createAndApply()
if (!config.skipTypeInfPass) {
TypeNodePass.withRegisteredTypes(astCreationPass.global.usedTypes.keys().asScala.toList, cpg).createAndApply()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,19 +453,21 @@ private[declarations] trait AstForTypeDeclsCreator { this: AstCreator =>
receiverAst.root.foreach(receiver => diffGraph.addEdge(initRoot, receiver, EdgeTypes.RECEIVER))

val capturesAsts =
usedCaptures.filterNot(outerClassAst.isDefined && _.name == NameConstants.OuterClass).zipWithIndex.map {
(usedCapture, index) =>
usedCaptures
.filterNot(outerClassAst.isDefined && _.name == NameConstants.OuterClass)
.zipWithIndex
.map { (usedCapture, index) =>
val identifier = NewIdentifier()
.name(usedCapture.name)
.code(usedCapture.name)
.typeFullName(usedCapture.typeFullName)
.lineNumber(initRoot.lineNumber)
.columnNumber(initRoot.columnNumber)

diffGraph.addEdge(identifier, usedCapture.node, EdgeTypes.REF)
val refsTo = Option.when(usedCapture.name != NameConstants.OuterClass)(usedCapture.node)

Ast(identifier)
}
Ast(identifier).withRefEdges(identifier, refsTo.toList)
}

(receiverAst :: args ++ outerClassAst.toList ++ capturesAsts)
.map { argAst =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.joern.javasrc2cpg.passes;

import io.joern.javasrc2cpg.util.NameConstants
import io.joern.x2cpg.Defines
import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.codepropertygraph.generated.EdgeTypes
import io.shiftleft.codepropertygraph.generated.nodes.{Method, TypeDecl}
import io.shiftleft.passes.ForkJoinParallelCpgPass
import io.shiftleft.semanticcpg.language.*

class OuterClassRefPass(cpg: Cpg) extends ForkJoinParallelCpgPass[TypeDecl](cpg) {
override def generateParts(): Array[TypeDecl] = cpg.typeDecl.toArray

override def runOnPart(diffGraph: DiffGraphBuilder, typeDecl: TypeDecl): Unit = {
typeDecl.method.nameExact(Defines.ConstructorMethodName).foreach { constructor =>
constructor.ast.isIdentifier.nameExact(NameConstants.OuterClass).filter(_.refsTo.isEmpty).foreach {
outerClassIdentifier =>
constructor.parameter.nameExact(NameConstants.OuterClass).foreach { outerClassParam =>
diffGraph.addEdge(outerClassIdentifier, outerClassParam, EdgeTypes.REF)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,17 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
@inline def constructors =
cpg.typeDecl.fullName("foo.Foo.enclosingMethod.Local").method.nameExact("<init>").sortBy(_.parameter.size)

"not have any orphan locals or parameters" in {
cpg.local.filter(_.astIn.isEmpty).l shouldBe List()
cpg.parameter.filter(_.astIn.isEmpty).l shouldBe List()
}

"have ref edges from the outer class identifier to the parameter" in {
inside(cpg.method.nameExact("<init>").filter(_.parameter.name.contains("ctxParam")).l) { case List(constructor) =>
constructor.ast.isIdentifier.name("outerClass").refsTo.l shouldBe constructor.parameter.name("outerClass").l
}
}

"have params for captured members for both constructors" in {
constructors.head.parameter.name.l shouldBe List("this", "outerClass", "outerParam")
constructors.last.parameter.name.l shouldBe List("this", "ctxParam", "outerClass", "outerParam")
Expand Down Expand Up @@ -869,7 +880,7 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
case List(call) =>
call.methodFullName shouldBe "foo.Foo.fooMethod.Local.<init>:void(int)"
call.signature shouldBe "void(int)"
pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
// pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
case result => fail(s"Unexpected result ${result}")
}
}
Expand Down Expand Up @@ -940,7 +951,7 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
case List(call) =>
call.methodFullName shouldBe "foo.Foo.foo.Local.<init>:void()"
call.signature shouldBe "void()"
pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
// pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
case result => fail(s"Unexpected result ${result}")
}
}
Expand Down Expand Up @@ -1001,7 +1012,7 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
case List(call) =>
call.methodFullName shouldBe "foo.Foo.fooMethod.Local.<init>:void()"
call.signature shouldBe "void()"
pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
// pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
case result => fail(s"Unexpected result ${result}")
}
}
Expand Down Expand Up @@ -1055,7 +1066,7 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
case List(call) =>
call.methodFullName shouldBe "foo.Foo.fooMethod.Local.<init>:void()"
call.signature shouldBe "void()"
pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
// pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
case result => fail(s"Unexpected result ${result}")
}
}
Expand Down Expand Up @@ -1108,7 +1119,7 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
case List(call) =>
call.methodFullName shouldBe "foo.Foo.fooMethod.Local.<init>:void(int)"
call.signature shouldBe "void(int)"
pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
// pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
case result => fail(s"Unexpected result ${result}")
}
}
Expand Down Expand Up @@ -1168,7 +1179,7 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
case List(call) =>
call.methodFullName shouldBe "foo.Foo.fooMethod.Local.<init>:void()"
call.signature shouldBe "void()"
pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
// pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
case result => fail(s"Unexpected result ${result}")
}
}
Expand Down Expand Up @@ -1217,7 +1228,7 @@ class LocalClassTests extends JavaSrcCode2CpgFixture {
case List(call) =>
call.methodFullName shouldBe "foo.Foo.fooMethod.Local.<init>:void(int)"
call.signature shouldBe "void(int)"
pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
// pendingUntilFixed(call.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH)
case result => fail(s"Unexpected result ${result}")
}
}
Expand Down

0 comments on commit f83f225

Please sign in to comment.