2020-06-24 21:39:07 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace Rector\FamilyTree\NodeAnalyzer;
|
|
|
|
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Stmt\Class_;
|
|
|
|
use PhpParser\Node\Stmt\Property;
|
2021-02-28 08:47:48 +01:00
|
|
|
use PHPStan\Analyser\Scope;
|
|
|
|
use PHPStan\Reflection\ClassReflection;
|
|
|
|
use Rector\Core\Exception\ShouldNotHappenException;
|
2020-06-24 21:39:07 +02:00
|
|
|
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
2020-07-19 18:02:11 +02:00
|
|
|
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
|
2020-09-10 14:56:54 +02:00
|
|
|
use Rector\NodeCollector\NodeCollector\NodeRepository;
|
2020-06-24 21:39:07 +02:00
|
|
|
use Rector\NodeNameResolver\NodeNameResolver;
|
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
|
|
|
|
|
|
|
final class PropertyUsageAnalyzer
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var NodeNameResolver
|
|
|
|
*/
|
|
|
|
private $nodeNameResolver;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var BetterNodeFinder
|
|
|
|
*/
|
|
|
|
private $betterNodeFinder;
|
|
|
|
|
2020-07-19 18:02:11 +02:00
|
|
|
/**
|
|
|
|
* @var FamilyRelationsAnalyzer
|
|
|
|
*/
|
|
|
|
private $familyRelationsAnalyzer;
|
|
|
|
|
2020-09-10 14:56:54 +02:00
|
|
|
/**
|
|
|
|
* @var NodeRepository
|
|
|
|
*/
|
|
|
|
private $nodeRepository;
|
|
|
|
|
2020-06-24 21:39:07 +02:00
|
|
|
public function __construct(
|
2020-07-19 18:02:11 +02:00
|
|
|
BetterNodeFinder $betterNodeFinder,
|
2020-07-26 09:49:22 +02:00
|
|
|
FamilyRelationsAnalyzer $familyRelationsAnalyzer,
|
2020-09-10 14:56:54 +02:00
|
|
|
NodeNameResolver $nodeNameResolver,
|
|
|
|
NodeRepository $nodeRepository
|
2020-06-24 21:39:07 +02:00
|
|
|
) {
|
|
|
|
$this->nodeNameResolver = $nodeNameResolver;
|
|
|
|
$this->betterNodeFinder = $betterNodeFinder;
|
2020-07-19 18:02:11 +02:00
|
|
|
$this->familyRelationsAnalyzer = $familyRelationsAnalyzer;
|
2020-09-10 14:56:54 +02:00
|
|
|
$this->nodeRepository = $nodeRepository;
|
2020-06-24 21:39:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function isPropertyFetchedInChildClass(Property $property): bool
|
|
|
|
{
|
|
|
|
$className = $property->getAttribute(AttributeKey::CLASS_NAME);
|
|
|
|
if ($className === null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-28 08:47:48 +01:00
|
|
|
$scope = $property->getAttribute(AttributeKey::SCOPE);
|
|
|
|
if (! $scope instanceof Scope) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$classReflection = $scope->getClassReflection();
|
|
|
|
if (! $classReflection instanceof ClassReflection) {
|
|
|
|
throw new ShouldNotHappenException();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($classReflection->isClass() && $classReflection->isFinal()) {
|
2020-06-24 21:39:07 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$propertyName = $this->nodeNameResolver->getName($property);
|
|
|
|
|
2021-02-28 08:47:48 +01:00
|
|
|
$childrenClassReflections = $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection);
|
|
|
|
|
|
|
|
foreach ($childrenClassReflections as $childClassReflection) {
|
|
|
|
$childClass = $this->nodeRepository->findClass($childClassReflection->getName());
|
2021-01-20 18:41:35 +07:00
|
|
|
if (! $childClass instanceof Class_) {
|
2020-06-24 21:39:07 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$isPropertyFetched = (bool) $this->betterNodeFinder->findFirst(
|
2020-12-25 01:22:45 +01:00
|
|
|
$childClass->stmts,
|
2020-09-01 19:56:30 +02:00
|
|
|
function (Node $node) use ($propertyName): bool {
|
2020-10-18 10:45:56 +02:00
|
|
|
return $this->nodeNameResolver->isLocalPropertyFetchNamed($node, $propertyName);
|
2020-06-24 21:39:07 +02:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
if ($isPropertyFetched) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|