Merge pull request #1515 from yondifon/fix-trait-inheritance-detection

BugFix: Fix toUseTrait to detect inherited and nested traits
This commit is contained in:
nuno maduro
2026-04-10 11:39:56 +01:00
committed by GitHub
6 changed files with 83 additions and 1 deletions

View File

@ -819,7 +819,22 @@ final class Expectation
return false;
}
if (! in_array($trait, $object->reflectionClass->getTraitNames(), true)) {
$currentClass = $object->reflectionClass;
$usedTraits = [];
do {
$classTraits = $currentClass->getTraits();
foreach ($classTraits as $traitReflection) {
$usedTraits[$traitReflection->getName()] = $traitReflection->getName();
$nestedTraits = $traitReflection->getTraits();
foreach ($nestedTraits as $nestedTrait) {
$usedTraits[$nestedTrait->getName()] = $nestedTrait->getName();
}
}
} while ($currentClass = $currentClass->getParentClass());
if (! array_key_exists($trait, $usedTraits)) {
return false;
}
}

View File

@ -14,3 +14,19 @@ test('failures', function () {
test('not failures', function () {
expect('Pest\Expectations\HigherOrderExpectation')->not->toUseTrait('Pest\Concerns\Retrievable');
})->throws(ArchExpectationFailedException::class);
test('trait inheritance - direct usage', function () {
expect('Tests\Fixtures\Arch\ToUseTrait\HasTrait\ParentClassWithTrait')->toUseTrait('Tests\Fixtures\Arch\ToUseTrait\HasTrait\TestTraitForInheritance');
});
test('trait inheritance - inherited usage', function () {
expect('Tests\Fixtures\Arch\ToUseTrait\HasInheritedTrait\ChildClassExtendingParent')->toUseTrait('Tests\Fixtures\Arch\ToUseTrait\HasTrait\TestTraitForInheritance');
});
test('trait inheritance - negative case', function () {
expect('Tests\Fixtures\Arch\ToUseTrait\HasInheritedTrait\ChildClassExtendingParent')->not->toUseTrait('NonExistentTrait');
});
test('nested trait inheritance', function () {
expect('Tests\Fixtures\Arch\ToUseTrait\HasInheritedTrait\ChildClassExtendingParent')->toUseTrait('Tests\Fixtures\Arch\ToUseTrait\HasNestedTrait\NestedTrait');
});

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseTrait\HasInheritedTrait;
use Tests\Fixtures\Arch\ToUseTrait\HasTrait\ParentClassWithTrait;
class ChildClassExtendingParent extends ParentClassWithTrait
{
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseTrait\HasNestedTrait;
trait NestedTrait
{
public function nestedMethod()
{
return 'nested';
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseTrait\HasTrait;
class ParentClassWithTrait
{
use TestTraitForInheritance;
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Tests\Fixtures\Arch\ToUseTrait\HasTrait;
use Tests\Fixtures\Arch\ToUseTrait\HasNestedTrait\NestedTrait;
trait TestTraitForInheritance
{
use NestedTrait;
public function testMethod()
{
return 'test';
}
}