diff --git a/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala b/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala index cacfc06fdd27..4f230dfc9875 100644 --- a/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala +++ b/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala @@ -245,6 +245,7 @@ class AstCreator( logger.debug( s"Trait use statement encountered. This is not yet supported. Location: $relativeFileName:${line(stmt)}" ) + Ast(unknownNode(stmt, code(stmt))) } diff --git a/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstForTypesCreator.scala b/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstForTypesCreator.scala index cad0585bbe8d..5e4eacec8810 100644 --- a/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstForTypesCreator.scala +++ b/joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstForTypesCreator.scala @@ -74,9 +74,12 @@ trait AstForTypesCreator(implicit withSchemaValidation: ValidationMode) { this: dynamicStmts: List[PhpStmt], staticStmts: List[PhpStmt] ): Ast = { - val inheritsFrom = (stmt.extendsNames ++ stmt.implementedInterfaces).map(_.name) + val useTraitNames = dynamicStmts.collect { case x: PhpTraitUseStmt => x }.flatMap(_.traits) + val inheritsFrom = (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(_.name) val inheritsFromMeta = - (stmt.extendsNames ++ stmt.implementedInterfaces).map(name => s"${name.name}$MetaTypeDeclExtension") + (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(name => + s"${name.name}$MetaTypeDeclExtension" + ) val className = stmt.name match { case Some(name) => name.name @@ -218,9 +221,27 @@ trait AstForTypesCreator(implicit withSchemaValidation: ValidationMode) { this: dynamicStmts: List[PhpStmt], staticStmts: List[PhpStmt] ): List[Ast] = { - val inheritsFrom = (stmt.extendsNames ++ stmt.implementedInterfaces).map(_.name) + /* + the `use ` can be used anywhere in a class definition, but the method is available to be called in any function in the class so we find all the traits before processing the rest of the class. + In the below sample, if we execute `(Foo.new())->foo()` it executes the `traitFunc` even though the `use ` is after the `foo` method + ```php + trait TraitA { + function traitFunc() {} + } + class Foo { + function foo() { + $this->traitFunc(); + } + use TraitA; + } + ``` + */ + val useTraitNames = dynamicStmts.collect { case x: PhpTraitUseStmt => x }.flatMap(_.traits) + val inheritsFrom = (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(_.name) val inheritsFromMeta = - (stmt.extendsNames ++ stmt.implementedInterfaces).map(name => s"${name.name}$MetaTypeDeclExtension") + (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(name => + s"${name.name}$MetaTypeDeclExtension" + ) val code = codeForClassStmt(stmt, name) val (dedupedName, fullName) = diff --git a/joern-cli/frontends/php2cpg/src/test/scala/io/joern/php2cpg/querying/TypeNodeTests.scala b/joern-cli/frontends/php2cpg/src/test/scala/io/joern/php2cpg/querying/TypeNodeTests.scala index 88f10da842e5..6bcce186520d 100644 --- a/joern-cli/frontends/php2cpg/src/test/scala/io/joern/php2cpg/querying/TypeNodeTests.scala +++ b/joern-cli/frontends/php2cpg/src/test/scala/io/joern/php2cpg/querying/TypeNodeTests.scala @@ -42,21 +42,29 @@ class TypeNodeTests extends PhpCode2CpgFixture { val cpg = code(""")" in { cpg.typeDecl.name(s"Baz${Domain.MetaTypeDeclExtension}").baseTypeDecl.l.map(_.name) shouldBe List( s"Bar${Domain.MetaTypeDeclExtension}", + s"TraitA${Domain.MetaTypeDeclExtension}", + s"TraitB${Domain.MetaTypeDeclExtension}", s"Foo${Domain.MetaTypeDeclExtension}" ) cpg.typeDecl.name(s"Baz${Domain.MetaTypeDeclExtension}").baseTypeDeclTransitive.l.map(_.name) shouldBe List( s"Bar${Domain.MetaTypeDeclExtension}", + s"TraitA${Domain.MetaTypeDeclExtension}", + s"TraitB${Domain.MetaTypeDeclExtension}", s"Foo${Domain.MetaTypeDeclExtension}" ) }