Skip to content

Commit 303f9dd

Browse files
committed
[php] Add trait names to inheritsFrom field
1 parent 35902a5 commit 303f9dd

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstCreator.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ class AstCreator(
245245
logger.debug(
246246
s"Trait use statement encountered. This is not yet supported. Location: $relativeFileName:${line(stmt)}"
247247
)
248+
248249
Ast(unknownNode(stmt, code(stmt)))
249250
}
250251

joern-cli/frontends/php2cpg/src/main/scala/io/joern/php2cpg/astcreation/AstForTypesCreator.scala

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,12 @@ trait AstForTypesCreator(implicit withSchemaValidation: ValidationMode) { this:
7474
dynamicStmts: List[PhpStmt],
7575
staticStmts: List[PhpStmt]
7676
): Ast = {
77-
val inheritsFrom = (stmt.extendsNames ++ stmt.implementedInterfaces).map(_.name)
77+
val useTraitNames = dynamicStmts.collect { case x: PhpTraitUseStmt => x }.flatMap(_.traits)
78+
val inheritsFrom = (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(_.name)
7879
val inheritsFromMeta =
79-
(stmt.extendsNames ++ stmt.implementedInterfaces).map(name => s"${name.name}$MetaTypeDeclExtension")
80+
(stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(name =>
81+
s"${name.name}$MetaTypeDeclExtension"
82+
)
8083

8184
val className = stmt.name match {
8285
case Some(name) => name.name
@@ -218,9 +221,27 @@ trait AstForTypesCreator(implicit withSchemaValidation: ValidationMode) { this:
218221
dynamicStmts: List[PhpStmt],
219222
staticStmts: List[PhpStmt]
220223
): List[Ast] = {
221-
val inheritsFrom = (stmt.extendsNames ++ stmt.implementedInterfaces).map(_.name)
224+
/*
225+
the `use <trait>` 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.
226+
In the below sample, if we execute `(Foo.new())->foo()` it executes the `traitFunc` even though the `use <trait>` is after the `foo` method
227+
```php
228+
trait TraitA {
229+
function traitFunc() {}
230+
}
231+
class Foo {
232+
function foo() {
233+
$this->traitFunc();
234+
}
235+
use TraitA;
236+
}
237+
```
238+
*/
239+
val useTraitNames = dynamicStmts.collect { case x: PhpTraitUseStmt => x }.flatMap(_.traits)
240+
val inheritsFrom = (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(_.name)
222241
val inheritsFromMeta =
223-
(stmt.extendsNames ++ stmt.implementedInterfaces).map(name => s"${name.name}$MetaTypeDeclExtension")
242+
(stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(name =>
243+
s"${name.name}$MetaTypeDeclExtension"
244+
)
224245
val code = codeForClassStmt(stmt, name)
225246

226247
val (dedupedName, fullName) =

joern-cli/frontends/php2cpg/src/test/scala/io/joern/php2cpg/querying/TypeNodeTests.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,16 @@ class TypeNodeTests extends PhpCode2CpgFixture {
4242
val cpg = code("""<?php
4343
|interface Foo {}
4444
|class Bar {}
45-
|class Baz extends Bar implements Foo {}
45+
|trait TraitA {}
46+
|trait TraitB {}
47+
|class Baz extends Bar implements Foo {
48+
| use TraitA, TraitB;
49+
|}
4650
|""".stripMargin)
4751

4852
"have baseTypeDecl for dynamic TYPE_DECL" in {
49-
cpg.typeDecl.name("Baz").baseTypeDecl.l.map(_.name) shouldBe List("Bar", "Foo")
50-
cpg.typeDecl.name("Baz").baseTypeDeclTransitive.l.map(_.name) shouldBe List("Bar", "Foo")
53+
cpg.typeDecl.name("Baz").baseTypeDecl.l.map(_.name) shouldBe List("Bar", "TraitA", "TraitB", "Foo")
54+
cpg.typeDecl.name("Baz").baseTypeDeclTransitive.l.map(_.name) shouldBe List("Bar", "TraitA", "TraitB", "Foo")
5155
}
5256

5357
"have baseTypeDecl steps for meta TYPE_DECL (<metaclass>)" in {

0 commit comments

Comments
 (0)