Skip to content

Commit 188445b

Browse files
authored
[CodeQuality] Skip mock property removal when used in a trait (#723)
1 parent 072d9b2 commit 188445b

3 files changed

Lines changed: 62 additions & 0 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\RemoveNeverUsedMockPropertyRector\Fixture;
4+
5+
use PHPUnit\Framework\MockObject\MockObject;
6+
use PHPUnit\Framework\TestCase;
7+
use Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\RemoveNeverUsedMockPropertyRector\Source\UsesMockPropertyTrait;
8+
9+
final class SkipIfUsedInTrait extends TestCase
10+
{
11+
use UsesMockPropertyTrait;
12+
13+
private MockObject $mockProperty;
14+
15+
protected function setUp(): void
16+
{
17+
$this->mockProperty = $this->createMock(\stdClass::class);
18+
$this->mockProperty->expects($this->once())
19+
->method('someMethod')
20+
->willReturn('someValue');
21+
}
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\RemoveNeverUsedMockPropertyRector\Source;
4+
5+
trait UsesMockPropertyTrait
6+
{
7+
public function useMock(): void
8+
{
9+
$this->mockProperty->someMethod();
10+
}
11+
}

‎rules/CodeQuality/Rector/Class_/RemoveNeverUsedMockPropertyRector.php‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
use PhpParser\Node\Stmt\ClassMethod;
1414
use PhpParser\Node\Stmt\Expression;
1515
use PhpParser\Node\Stmt\Property;
16+
use PhpParser\Node\Stmt\Trait_;
17+
use Rector\PhpParser\AstResolver;
1618
use Rector\PhpParser\Node\BetterNodeFinder;
1719
use Rector\PhpParser\NodeFinder\PropertyFetchFinder;
1820
use Rector\PHPUnit\CodeQuality\NodeAnalyser\MockObjectPropertyDetector;
@@ -32,6 +34,7 @@ public function __construct(
3234
private readonly MockObjectPropertyDetector $mockObjectPropertyDetector,
3335
private readonly PropertyFetchFinder $propertyFetchFinder,
3436
private readonly BetterNodeFinder $betterNodeFinder,
37+
private readonly AstResolver $astResolver,
3538
) {
3639
}
3740

@@ -235,9 +238,35 @@ private function resolvePropertyNamesToRemove(array $propertyNamesToCreateMockMe
235238
continue;
236239
}
237240

241+
// the property might be used in a used trait, skip removal to stay safe
242+
if ($this->isPropertyUsedInTrait($class, $propertyName)) {
243+
continue;
244+
}
245+
238246
$propertyNamesToRemove[] = $propertyName;
239247
}
240248

241249
return $propertyNamesToRemove;
242250
}
251+
252+
private function isPropertyUsedInTrait(Class_ $class, string $propertyName): bool
253+
{
254+
foreach ($class->getTraitUses() as $traitUse) {
255+
foreach ($traitUse->traits as $traitName) {
256+
$trait = $this->astResolver->resolveClassFromName($traitName->toString());
257+
if (! $trait instanceof Trait_) {
258+
continue;
259+
}
260+
261+
$propertyFetches = $this->betterNodeFinder->findInstancesOf($trait, [PropertyFetch::class]);
262+
foreach ($propertyFetches as $propertyFetch) {
263+
if ($this->isName($propertyFetch->name, $propertyName)) {
264+
return true;
265+
}
266+
}
267+
}
268+
}
269+
270+
return false;
271+
}
243272
}

0 commit comments

Comments
 (0)