Skip to content

Commit 5db8a97

Browse files
authored
[php] add trait names for use trait to inheritsFrom field (#5613)
* [php] Add trait names to inheritsFrom field * fix test
1 parent 7a79301 commit 5db8a97

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-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
@@ -209,6 +209,7 @@ class AstCreator(
209209
logger.debug(
210210
s"Trait use statement encountered. This is not yet supported. Location: $relativeFileName:${line(stmt)}"
211211
)
212+
212213
Ast(unknownNode(stmt, code(stmt)))
213214
}
214215

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
@@ -66,9 +66,12 @@ trait AstForTypesCreator(implicit withSchemaValidation: ValidationMode) { this:
6666
dynamicStmts: List[PhpStmt],
6767
staticStmts: List[PhpStmt]
6868
): Ast = {
69-
val inheritsFrom = (stmt.extendsNames ++ stmt.implementedInterfaces).map(_.name)
69+
val useTraitNames = dynamicStmts.collect { case x: PhpTraitUseStmt => x }.flatMap(_.traits)
70+
val inheritsFrom = (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(_.name)
7071
val inheritsFromMeta =
71-
(stmt.extendsNames ++ stmt.implementedInterfaces).map(name => s"${name.name}$MetaTypeDeclExtension")
72+
(stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(name =>
73+
s"${name.name}$MetaTypeDeclExtension"
74+
)
7275

7376
val className = stmt.name match {
7477
case Some(name) => name.name
@@ -208,9 +211,27 @@ trait AstForTypesCreator(implicit withSchemaValidation: ValidationMode) { this:
208211
dynamicStmts: List[PhpStmt],
209212
staticStmts: List[PhpStmt]
210213
): List[Ast] = {
211-
val inheritsFrom = (stmt.extendsNames ++ stmt.implementedInterfaces).map(_.name)
214+
/*
215+
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.
216+
In the below sample, if we execute `(Foo.new())->foo()` it executes the `traitFunc` even though the `use <trait>` is after the `foo` method
217+
```php
218+
trait TraitA {
219+
function traitFunc() {}
220+
}
221+
class Foo {
222+
function foo() {
223+
$this->traitFunc();
224+
}
225+
use TraitA;
226+
}
227+
```
228+
*/
229+
val useTraitNames = dynamicStmts.collect { case x: PhpTraitUseStmt => x }.flatMap(_.traits)
230+
val inheritsFrom = (stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(_.name)
212231
val inheritsFromMeta =
213-
(stmt.extendsNames ++ stmt.implementedInterfaces).map(name => s"${name.name}$MetaTypeDeclExtension")
232+
(stmt.extendsNames ++ useTraitNames ++ stmt.implementedInterfaces).map(name =>
233+
s"${name.name}$MetaTypeDeclExtension"
234+
)
214235
val code = codeForClassStmt(stmt, name)
215236

216237
val (dedupedName, fullName) =

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,29 @@ 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 {
5458
cpg.typeDecl.name(s"Baz${Domain.MetaTypeDeclExtension}").baseTypeDecl.l.map(_.name) shouldBe List(
5559
s"Bar${Domain.MetaTypeDeclExtension}",
60+
s"TraitA${Domain.MetaTypeDeclExtension}",
61+
s"TraitB${Domain.MetaTypeDeclExtension}",
5662
s"Foo${Domain.MetaTypeDeclExtension}"
5763
)
5864
cpg.typeDecl.name(s"Baz${Domain.MetaTypeDeclExtension}").baseTypeDeclTransitive.l.map(_.name) shouldBe List(
5965
s"Bar${Domain.MetaTypeDeclExtension}",
66+
s"TraitA${Domain.MetaTypeDeclExtension}",
67+
s"TraitB${Domain.MetaTypeDeclExtension}",
6068
s"Foo${Domain.MetaTypeDeclExtension}"
6169
)
6270
}

0 commit comments

Comments
 (0)