add property reflection resolver (#317)

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Tomas Votruba 2021-06-28 01:25:02 +02:00 committed by GitHub
parent f4ff000d45
commit 947da2c680
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 66 additions and 39 deletions

View File

@ -271,7 +271,7 @@ final class PhpDocInfo
// FQN check
$resolvedClass = $identifierTypeNode->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
if (!is_string($resolvedClass)) {
if (! is_string($resolvedClass)) {
continue;
}

View File

@ -5,13 +5,8 @@ declare(strict_types=1);
namespace Rector\NodeCollector\NodeCollector;
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use Rector\Core\Exception\ShouldNotHappenException;

View File

@ -10,7 +10,6 @@ use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\ObjectType;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\ValueObject\OldToNewType;
use Rector\StaticTypeMapper\StaticTypeMapper;

View File

@ -20,7 +20,6 @@ use Rector\Core\NodeManipulator\AssignManipulator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\ReadWrite\Guard\VariableToConstantGuard;
use Webmozart\Assert\Assert;
final class ReadWritePropertyAnalyzer
{
@ -32,7 +31,7 @@ final class ReadWritePropertyAnalyzer
) {
}
public function isRead(PropertyFetch|StaticPropertyFetch $node): bool
public function isRead(PropertyFetch | StaticPropertyFetch $node): bool
{
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if (! $parent instanceof Node) {

View File

@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Trait_;
use Rector\Core\NodeManipulator\PropertyManipulator;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Removing\NodeManipulator\ComplexNodeRemover;

View File

@ -6,7 +6,6 @@ namespace Rector\Defluent\NodeAnalyzer;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Defluent\Contract\ValueObject\FirstCallFactoryAwareInterface;

View File

@ -109,7 +109,7 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
/**
* @return Expr[]
*/
private function getNonVariableArguments(FuncCall|MethodCall|StaticCall $call): array
private function getNonVariableArguments(FuncCall | MethodCall | StaticCall $call): array
{
$arguments = [];

View File

@ -13,7 +13,6 @@ use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\NodeNameResolver\NodeNameResolver;
use Webmozart\Assert\Assert;
/**
* This class renames node identifier, e.g. ClassMethod rename:
@ -31,8 +30,10 @@ final class IdentifierManipulator
/**
* @param string[] $renameMethodMap
*/
public function renameNodeWithMap(ClassConstFetch|MethodCall|PropertyFetch|StaticCall|ClassMethod $node, array $renameMethodMap): void
{
public function renameNodeWithMap(
ClassConstFetch | MethodCall | PropertyFetch | StaticCall | ClassMethod $node,
array $renameMethodMap
): void {
$oldNodeMethodName = $this->resolveOldMethodName($node);
if ($oldNodeMethodName === null) {
return;
@ -41,8 +42,10 @@ final class IdentifierManipulator
$node->name = new Identifier($renameMethodMap[$oldNodeMethodName]);
}
public function removeSuffix(ClassConstFetch|MethodCall|PropertyFetch|StaticCall|ClassMethod $node, string $suffixToRemove): void
{
public function removeSuffix(
ClassConstFetch | MethodCall | PropertyFetch | StaticCall | ClassMethod $node,
string $suffixToRemove
): void {
$name = $this->nodeNameResolver->getName($node);
if ($name === null) {
return;

View File

@ -6,15 +6,13 @@ namespace Rector\TypeDeclaration\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\UnionType;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -26,7 +24,8 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class ReturnTypeFromStrictTypedPropertyRector extends AbstractRector
{
public function __construct(
private TypeFactory $typeFactory
private TypeFactory $typeFactory,
private ReflectionResolver $reflectionResolver
) {
}
@ -83,16 +82,11 @@ CODE_SAMPLE
return null;
}
$propertyTypeNodes = $this->resolveReturnPropertyTypeNodes($node);
if ($propertyTypeNodes === []) {
$propertyTypes = $this->resolveReturnPropertyType($node);
if ($propertyTypes === []) {
return null;
}
$propertyTypes = [];
foreach ($propertyTypeNodes as $propertyTypeNode) {
$propertyTypes[] = $this->staticTypeMapper->mapPhpParserNodePHPStanType($propertyTypeNode);
}
// add type to return type
$propertyType = $this->typeFactory->createMixedPassedOrUnionType($propertyTypes);
if ($propertyType instanceof MixedType) {
@ -110,14 +104,15 @@ CODE_SAMPLE
}
/**
* @return array<Identifier|Name|NullableType|UnionType>
* @return Type[]
*/
private function resolveReturnPropertyTypeNodes(ClassMethod $classMethod): array
private function resolveReturnPropertyType(ClassMethod $classMethod): array
{
/** @var Return_[] $returns */
$returns = $this->betterNodeFinder->findInstanceOf($classMethod, Return_::class);
$propertyTypes = [];
foreach ($returns as $return) {
if ($return->expr === null) {
return [];
@ -127,16 +122,18 @@ CODE_SAMPLE
return [];
}
$property = $this->nodeRepository->findPropertyByPropertyFetch($return->expr);
if (! $property instanceof Property) {
$propertyReflection = $this->reflectionResolver->resolvePropertyReflectionFromPropertyFetch(
$return->expr
);
if (! $propertyReflection instanceof PhpPropertyReflection) {
return [];
}
if ($property->type === null) {
if ($propertyReflection->getNativeType() instanceof MixedType) {
return [];
}
$propertyTypes[] = $property->type;
$propertyTypes[] = $propertyReflection->getNativeType();
}
return $propertyTypes;

View File

@ -17,7 +17,6 @@ use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\Php\PhpFunctionReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;

View File

@ -7,13 +7,14 @@ namespace Rector\Core\Reflection;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\TypeWithClassName;
@ -150,8 +151,44 @@ final class ReflectionResolver
return $this->resolveMethodReflection($newClassType->getClassName(), MethodName::CONSTRUCT, $scope);
}
private function resolveFunctionReflectionFromFuncCall(FuncCall $funcCall): FunctionReflection | MethodReflection | null
public function resolvePropertyReflectionFromPropertyFetch(PropertyFetch $propertyFetch): ?PhpPropertyReflection
{
$fetcheeType = $this->nodeTypeResolver->resolve($propertyFetch->var);
if (! $fetcheeType instanceof TypeWithClassName) {
return null;
}
if (! $this->reflectionProvider->hasClass($fetcheeType->getClassName())) {
return null;
}
$classReflection = $this->reflectionProvider->getClass($fetcheeType->getClassName());
$propertyName = $this->nodeNameResolver->getName($propertyFetch->name);
if ($propertyName === null) {
return null;
}
if (! $classReflection->hasProperty($propertyName)) {
return null;
}
$scope = $propertyFetch->getAttribute(AttributeKey::SCOPE);
if ($scope instanceof Scope) {
$propertyRelfection = $classReflection->getProperty($propertyName, $scope);
if ($propertyRelfection instanceof PhpPropertyReflection) {
return $propertyRelfection;
}
return null;
}
return $classReflection->getNativeProperty($propertyName);
}
private function resolveFunctionReflectionFromFuncCall(
FuncCall $funcCall
): FunctionReflection | MethodReflection | null {
$scope = $funcCall->getAttribute(AttributeKey::SCOPE);
if ($funcCall->name instanceof Name) {