Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name := "joern"
ThisBuild / organization := "io.joern"
ThisBuild / scalaVersion := "3.6.4"

val cpgVersion = "1.7.43"
val cpgVersion = "1.7.45"

lazy val joerncli = Projects.joerncli
lazy val querydb = Projects.querydb
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ trait AstForCallExpressionsCreator { this: AstCreator =>
}

val receiverType = scopeAsts.rootType.filter(_ != TypeConstants.Any).orElse(receiverTypeOption)
val staticReceiver = Option.when(dispatchType == DispatchTypes.STATIC_DISPATCH)(receiverType).flatten

val argumentsCode = getArgumentCodeString(call.getArguments)
val codePrefix = scopeAsts.headOption
Expand All @@ -103,6 +104,7 @@ trait AstForCallExpressionsCreator { this: AstCreator =>
.lineNumber(line(call))
.columnNumber(column(call))
.typeFullName(expressionTypeFullName.getOrElse(defaultTypeFallback()))
.staticReceiver(staticReceiver)

callAst(callRoot, argumentAsts, scopeAsts.headOption)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ class NewCallTests extends JavaSrcCode2CpgFixture {
|
|""".stripMargin)

cpg.call.name("valueOf").methodFullName.l shouldBe List("java.lang.String.valueOf:java.lang.String(boolean)")
inside(cpg.call.name("valueOf").l) { case List(valueOfCall) =>
valueOfCall.methodFullName shouldBe "java.lang.String.valueOf:java.lang.String(boolean)"
valueOfCall.staticReceiver shouldBe Some("java.lang.String")
}
}

"they are instance methods imported from java.lang.* should be resolved" in {
Expand Down Expand Up @@ -131,7 +134,51 @@ class NewCallTests extends JavaSrcCode2CpgFixture {
|}
|""".stripMargin)

cpg.call.name("foo").methodFullName.l shouldBe List("foo.Foo.foo:java.lang.String()")
inside(cpg.call.name("foo").l) { case List(fooCall) =>
fooCall.methodFullName shouldBe "foo.Foo.foo:java.lang.String()"
fooCall.staticReceiver shouldBe Some("foo.Foo")
}
}

"calls to inherited static methods" should {
val cpg = code(
"""
|package foo;
|
|class Foo {
| public static String foo() {
| return "FOO";
| }
|}
|""".stripMargin)
.moreCode(
"""
|package bar;
|
|import foo.Foo;
|
|class Bar extends Foo { }
|""".stripMargin)
.moreCode(
"""
|package baz;
|
|import bar.Bar;
|
|class Baz {
| void test() {
| Bar.foo();
| }
|}
|""".stripMargin
)

"have the correct staticReceiver set" in {
inside(cpg.call.name("foo").l) { case List(fooCall) =>
fooCall.methodFullName shouldBe "bar.Bar.foo:java.lang.String()"
fooCall.staticReceiver shouldBe Some("bar.Bar")
}
}
}

"calls with unresolved receivers should have the correct fullnames" in {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ trait AstCreatorHelper(disableFileContent: Boolean)(implicit withSchemaValidatio
}
}

private def getTypeDeclPrefix: Option[String] =
protected def getTypeDeclPrefix: Option[String] =
scope.getEnclosingTypeDeclTypeName.filterNot(_ == NamespaceTraversal.globalNamespaceName)

protected def codeForMethodCall(call: PhpCallExpr, targetAst: Ast, name: String): String = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,14 @@ trait AstForExpressionsCreator(implicit withSchemaValidation: ValidationMode) {
case _ => getMfn(call, name)
}

val callRoot = callNode(call, code, name, fullName, dispatchType, None, Some(Defines.Any))
val staticReceiver = call.target.collect {
case nameExpr: PhpNameExpr if nameExpr.name == NameConstants.Self =>
getTypeDeclPrefix.map(name => s"$name$MetaTypeDeclExtension")
case nameExpr: PhpNameExpr =>
Option(s"${nameExpr.name}$MetaTypeDeclExtension")
}.flatten

val callRoot = callNode(call, code, name, fullName, dispatchType, None, Some(Defines.Any), staticReceiver)

callAst(callRoot, arguments)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class CallTests extends PhpCode2CpgFixture {
barCall.receiver.isEmpty shouldBe true
barCall.dispatchType shouldBe DispatchTypes.STATIC_DISPATCH
barCall.code shouldBe "self::bar($x)"
barCall.staticReceiver shouldBe Some("ClassA<metaclass>")
}
}

Expand Down Expand Up @@ -337,13 +338,15 @@ class CallTests extends PhpCode2CpgFixture {
test1.name shouldBe "test1"
test1.methodFullName shouldBe "Foo\\Bar\\baz<metaclass>.test1"
test1.dispatchType shouldBe DispatchTypes.STATIC_DISPATCH
test1.staticReceiver shouldBe Some("Foo\\Bar\\baz<metaclass>")
}

"be unknown in the case of dynamic calls" in {
val test2 = cpg.call("test2").head
test2.name shouldBe "test2"
test2.methodFullName shouldBe s"${Defines.UnresolvedNamespace}.test2"
test2.dispatchType shouldBe DispatchTypes.DYNAMIC_DISPATCH
test2.staticReceiver shouldBe None
}
}

Expand Down Expand Up @@ -384,5 +387,4 @@ class CallTests extends PhpCode2CpgFixture {
construct.typeFullName shouldBe Defines.Any
construct.dynamicTypeHintFullName shouldBe Seq.empty
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,16 @@ trait AstNodeBuilder[Node, NodeProcessor] { this: NodeProcessor =>
methodFullName: String,
dispatchType: String,
signature: Option[String],
typeFullName: Option[String]
typeFullName: Option[String],
staticReceiver: Option[String] = None
): NewCall = {
val node_ =
NewCall()
.code(code)
.name(name)
.methodFullName(methodFullName)
.dispatchType(dispatchType)
.staticReceiver(staticReceiver)
.lineNumber(line(node))
.columnNumber(column(node))
signature.foreach { s => node_.signature(s) }
Expand Down
Loading