mirror of https://github.com/rectorphp/rector.git
Updated Rector to commit 75d1dca2ef328d91cff2b642e79f1c442696d0a1
75d1dca2ef
Don't get type from PropertyFetch for not natively typed properties (#3327)
This commit is contained in:
parent
e30c207496
commit
ab40a52407
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Rector\TypeDeclaration\TypeAnalyzer;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\Php\PhpPropertyReflection;
|
||||
use PHPStan\Reflection\PropertyReflection;
|
||||
use PHPStan\Reflection\WrapperPropertyReflection;
|
||||
use PHPStan\Type\MixedType;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
final class PropertyFetchTypeAnalyzer
|
||||
{
|
||||
public function isPropertyFetchExprNotNativelyTyped(Expr $expr) : bool
|
||||
{
|
||||
if (!$expr instanceof PropertyFetch) {
|
||||
return \false;
|
||||
}
|
||||
if (!$expr->name instanceof Identifier) {
|
||||
return \false;
|
||||
}
|
||||
$scope = $expr->getAttribute(AttributeKey::SCOPE);
|
||||
if (!$scope instanceof Scope) {
|
||||
return \false;
|
||||
}
|
||||
$propertyName = $expr->name->toString();
|
||||
$propertyHolderType = $scope->getType($expr->var);
|
||||
if (!$propertyHolderType->hasProperty($propertyName)->yes()) {
|
||||
return \false;
|
||||
}
|
||||
$propertyReflection = $propertyHolderType->getProperty($propertyName, $scope);
|
||||
$phpPropertyReflection = $this->getNativeReflectionForProperty($propertyReflection);
|
||||
if ($phpPropertyReflection === null) {
|
||||
return \false;
|
||||
}
|
||||
return $phpPropertyReflection->getNativeType() instanceof MixedType;
|
||||
}
|
||||
private function getNativeReflectionForProperty(PropertyReflection $propertyReflection) : ?PhpPropertyReflection
|
||||
{
|
||||
$reflection = $propertyReflection;
|
||||
while ($reflection instanceof WrapperPropertyReflection) {
|
||||
$reflection = $reflection->getOriginalReflection();
|
||||
}
|
||||
if (!$reflection instanceof PhpPropertyReflection) {
|
||||
return null;
|
||||
}
|
||||
return $reflection;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ use Rector\TypeDeclaration\AlreadyAssignDetector\ConstructorAssignDetector;
|
|||
use Rector\TypeDeclaration\AlreadyAssignDetector\NullTypeAssignDetector;
|
||||
use Rector\TypeDeclaration\AlreadyAssignDetector\PropertyDefaultAssignDetector;
|
||||
use Rector\TypeDeclaration\Matcher\PropertyAssignMatcher;
|
||||
use Rector\TypeDeclaration\TypeAnalyzer\PropertyFetchTypeAnalyzer;
|
||||
/**
|
||||
* @deprecated
|
||||
* @todo Split into many narrow-focused rules
|
||||
|
@ -83,7 +84,12 @@ final class AssignToPropertyTypeInferer
|
|||
* @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
|
||||
*/
|
||||
private $propertyFetchAnalyzer;
|
||||
public function __construct(ConstructorAssignDetector $constructorAssignDetector, PropertyAssignMatcher $propertyAssignMatcher, PropertyDefaultAssignDetector $propertyDefaultAssignDetector, NullTypeAssignDetector $nullTypeAssignDetector, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, NodeTypeResolver $nodeTypeResolver, ExprAnalyzer $exprAnalyzer, ValueResolver $valueResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer)
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\TypeDeclaration\TypeAnalyzer\PropertyFetchTypeAnalyzer
|
||||
*/
|
||||
private $propertyFetchTypeAnalyzer;
|
||||
public function __construct(ConstructorAssignDetector $constructorAssignDetector, PropertyAssignMatcher $propertyAssignMatcher, PropertyDefaultAssignDetector $propertyDefaultAssignDetector, NullTypeAssignDetector $nullTypeAssignDetector, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, NodeTypeResolver $nodeTypeResolver, ExprAnalyzer $exprAnalyzer, ValueResolver $valueResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer, PropertyFetchTypeAnalyzer $propertyFetchTypeAnalyzer)
|
||||
{
|
||||
$this->constructorAssignDetector = $constructorAssignDetector;
|
||||
$this->propertyAssignMatcher = $propertyAssignMatcher;
|
||||
|
@ -95,37 +101,14 @@ final class AssignToPropertyTypeInferer
|
|||
$this->exprAnalyzer = $exprAnalyzer;
|
||||
$this->valueResolver = $valueResolver;
|
||||
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
|
||||
$this->propertyFetchTypeAnalyzer = $propertyFetchTypeAnalyzer;
|
||||
}
|
||||
public function inferPropertyInClassLike(Property $property, string $propertyName, ClassLike $classLike) : ?Type
|
||||
{
|
||||
$assignedExprTypes = [];
|
||||
$hasAssignDynamicPropertyValue = \false;
|
||||
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($classLike->stmts, function (Node $node) use($propertyName, &$assignedExprTypes, &$hasAssignDynamicPropertyValue) : ?int {
|
||||
if (!$node instanceof Assign) {
|
||||
return null;
|
||||
}
|
||||
$expr = $this->propertyAssignMatcher->matchPropertyAssignExpr($node, $propertyName);
|
||||
if (!$expr instanceof Expr) {
|
||||
if (!$this->propertyFetchAnalyzer->isLocalPropertyFetch($node->var)) {
|
||||
return null;
|
||||
}
|
||||
/** @var PropertyFetch|StaticPropertyFetch $assignVar */
|
||||
$assignVar = $node->var;
|
||||
if (!$assignVar->name instanceof Identifier) {
|
||||
$hasAssignDynamicPropertyValue = \true;
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if ($this->exprAnalyzer->isNonTypedFromParam($node->expr)) {
|
||||
return null;
|
||||
}
|
||||
$assignedExprTypes[] = $this->resolveExprStaticTypeIncludingDimFetch($node);
|
||||
return null;
|
||||
});
|
||||
if ($hasAssignDynamicPropertyValue) {
|
||||
if ($this->hasAssignDynamicPropertyValue($classLike, $propertyName)) {
|
||||
return null;
|
||||
}
|
||||
$assignedExprTypes = $this->getAssignedExprTypes($classLike, $propertyName);
|
||||
if ($this->shouldAddNullType($classLike, $propertyName, $assignedExprTypes)) {
|
||||
$assignedExprTypes[] = new NullType();
|
||||
}
|
||||
|
@ -194,4 +177,53 @@ final class AssignToPropertyTypeInferer
|
|||
}
|
||||
return !$hasPropertyDefaultValue;
|
||||
}
|
||||
private function hasAssignDynamicPropertyValue(ClassLike $classLike, string $propertyName) : bool
|
||||
{
|
||||
$hasAssignDynamicPropertyValue = \false;
|
||||
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($classLike->stmts, function (Node $node) use($propertyName, &$hasAssignDynamicPropertyValue) : ?int {
|
||||
if (!$node instanceof Assign) {
|
||||
return null;
|
||||
}
|
||||
$expr = $this->propertyAssignMatcher->matchPropertyAssignExpr($node, $propertyName);
|
||||
if (!$expr instanceof Expr) {
|
||||
if (!$this->propertyFetchAnalyzer->isLocalPropertyFetch($node->var)) {
|
||||
return null;
|
||||
}
|
||||
/** @var PropertyFetch|StaticPropertyFetch $assignVar */
|
||||
$assignVar = $node->var;
|
||||
if (!$assignVar->name instanceof Identifier) {
|
||||
$hasAssignDynamicPropertyValue = \true;
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return $hasAssignDynamicPropertyValue;
|
||||
}
|
||||
/**
|
||||
* @return array<Type>
|
||||
*/
|
||||
private function getAssignedExprTypes(ClassLike $classLike, string $propertyName) : array
|
||||
{
|
||||
$assignedExprTypes = [];
|
||||
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($classLike->stmts, function (Node $node) use($propertyName, &$assignedExprTypes) : ?int {
|
||||
if (!$node instanceof Assign) {
|
||||
return null;
|
||||
}
|
||||
$expr = $this->propertyAssignMatcher->matchPropertyAssignExpr($node, $propertyName);
|
||||
if (!$expr instanceof Expr) {
|
||||
return null;
|
||||
}
|
||||
if ($this->propertyFetchAnalyzer->isPropertyFetch($node->expr) && $this->propertyFetchTypeAnalyzer->isPropertyFetchExprNotNativelyTyped($node->expr)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->exprAnalyzer->isNonTypedFromParam($node->expr)) {
|
||||
return null;
|
||||
}
|
||||
$assignedExprTypes[] = $this->resolveExprStaticTypeIncludingDimFetch($node);
|
||||
return null;
|
||||
});
|
||||
return $assignedExprTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ use PHPStan\Type\Type;
|
|||
use PHPStan\Type\TypeCombinator;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\Core\NodeAnalyzer\ParamAnalyzer;
|
||||
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
|
||||
use Rector\Core\NodeManipulator\ClassMethodPropertyFetchManipulator;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
|
@ -33,6 +34,7 @@ use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
|
|||
use Rector\StaticTypeMapper\StaticTypeMapper;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
|
||||
use Rector\TypeDeclaration\TypeAnalyzer\PropertyFetchTypeAnalyzer;
|
||||
use Rector\TypeDeclaration\TypeInferer\AssignToPropertyTypeInferer;
|
||||
/**
|
||||
* @deprecated
|
||||
|
@ -95,7 +97,17 @@ final class TrustedClassMethodPropertyTypeInferer
|
|||
* @var \Rector\NodeTypeResolver\TypeComparator\TypeComparator
|
||||
*/
|
||||
private $typeComparator;
|
||||
public function __construct(ClassMethodPropertyFetchManipulator $classMethodPropertyFetchManipulator, ReflectionProvider $reflectionProvider, NodeNameResolver $nodeNameResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, StaticTypeMapper $staticTypeMapper, NodeTypeResolver $nodeTypeResolver, BetterNodeFinder $betterNodeFinder, ParamAnalyzer $paramAnalyzer, AssignToPropertyTypeInferer $assignToPropertyTypeInferer, TypeComparator $typeComparator)
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
|
||||
*/
|
||||
private $propertyFetchAnalyzer;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\TypeDeclaration\TypeAnalyzer\PropertyFetchTypeAnalyzer
|
||||
*/
|
||||
private $propertyFetchTypeAnalyzer;
|
||||
public function __construct(ClassMethodPropertyFetchManipulator $classMethodPropertyFetchManipulator, ReflectionProvider $reflectionProvider, NodeNameResolver $nodeNameResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, StaticTypeMapper $staticTypeMapper, NodeTypeResolver $nodeTypeResolver, BetterNodeFinder $betterNodeFinder, ParamAnalyzer $paramAnalyzer, AssignToPropertyTypeInferer $assignToPropertyTypeInferer, TypeComparator $typeComparator, PropertyFetchAnalyzer $propertyFetchAnalyzer, PropertyFetchTypeAnalyzer $propertyFetchTypeAnalyzer)
|
||||
{
|
||||
$this->classMethodPropertyFetchManipulator = $classMethodPropertyFetchManipulator;
|
||||
$this->reflectionProvider = $reflectionProvider;
|
||||
|
@ -108,6 +120,8 @@ final class TrustedClassMethodPropertyTypeInferer
|
|||
$this->paramAnalyzer = $paramAnalyzer;
|
||||
$this->assignToPropertyTypeInferer = $assignToPropertyTypeInferer;
|
||||
$this->typeComparator = $typeComparator;
|
||||
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
|
||||
$this->propertyFetchTypeAnalyzer = $propertyFetchTypeAnalyzer;
|
||||
}
|
||||
public function inferProperty(Property $property, ClassMethod $classMethod) : Type
|
||||
{
|
||||
|
@ -126,6 +140,9 @@ final class TrustedClassMethodPropertyTypeInferer
|
|||
$assignedExprs = $this->classMethodPropertyFetchManipulator->findAssignsToPropertyName($classMethod, $propertyName);
|
||||
$resolvedTypes = [];
|
||||
foreach ($assignedExprs as $assignedExpr) {
|
||||
if ($this->propertyFetchAnalyzer->isPropertyFetch($assignedExpr) && $this->propertyFetchTypeAnalyzer->isPropertyFetchExprNotNativelyTyped($assignedExpr)) {
|
||||
continue;
|
||||
}
|
||||
$resolvedTypes[] = $this->nodeTypeResolver->getType($assignedExpr);
|
||||
}
|
||||
if ($resolvedTypes === []) {
|
||||
|
|
|
@ -19,12 +19,12 @@ final class VersionResolver
|
|||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const PACKAGE_VERSION = '913ccba104bde2c858fba76ae56f1c4d7c35b067';
|
||||
public const PACKAGE_VERSION = '75d1dca2ef328d91cff2b642e79f1c442696d0a1';
|
||||
/**
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const RELEASE_DATE = '2023-02-06 16:33:15';
|
||||
public const RELEASE_DATE = '2023-02-06 17:06:42';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
|
|
@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
|
|||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit0a672635d29f42a014258712107ce131::getLoader();
|
||||
return ComposerAutoloaderInit6ed8c1e889d5a966c6689f7b3517e8f3::getLoader();
|
||||
|
|
|
@ -2790,6 +2790,7 @@ return array(
|
|||
'Rector\\TypeDeclaration\\TypeAnalyzer\\AlwaysStrictBoolExprAnalyzer' => $baseDir . '/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictBoolExprAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\AlwaysStrictScalarExprAnalyzer' => $baseDir . '/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictScalarExprAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\GenericClassStringTypeNormalizer' => $baseDir . '/rules/TypeDeclaration/TypeAnalyzer/GenericClassStringTypeNormalizer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\PropertyFetchTypeAnalyzer' => $baseDir . '/rules/TypeDeclaration/TypeAnalyzer/PropertyFetchTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\ReturnStrictTypeAnalyzer' => $baseDir . '/rules/TypeDeclaration/TypeAnalyzer/ReturnStrictTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\StrictReturnClassConstReturnTypeAnalyzer' => $baseDir . '/rules/TypeDeclaration/TypeAnalyzer/StrictReturnClassConstReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeInferer\\AssignToPropertyTypeInferer' => $baseDir . '/rules/TypeDeclaration/TypeInferer/AssignToPropertyTypeInferer.php',
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit0a672635d29f42a014258712107ce131
|
||||
class ComposerAutoloaderInit6ed8c1e889d5a966c6689f7b3517e8f3
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
|
@ -22,17 +22,17 @@ class ComposerAutoloaderInit0a672635d29f42a014258712107ce131
|
|||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit0a672635d29f42a014258712107ce131', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInit6ed8c1e889d5a966c6689f7b3517e8f3', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit0a672635d29f42a014258712107ce131', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit6ed8c1e889d5a966c6689f7b3517e8f3', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit0a672635d29f42a014258712107ce131::getInitializer($loader));
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit6ed8c1e889d5a966c6689f7b3517e8f3::getInitializer($loader));
|
||||
|
||||
$loader->setClassMapAuthoritative(true);
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit0a672635d29f42a014258712107ce131::$files;
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit6ed8c1e889d5a966c6689f7b3517e8f3::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit0a672635d29f42a014258712107ce131
|
||||
class ComposerStaticInit6ed8c1e889d5a966c6689f7b3517e8f3
|
||||
{
|
||||
public static $files = array (
|
||||
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
|
||||
|
@ -3035,6 +3035,7 @@ class ComposerStaticInit0a672635d29f42a014258712107ce131
|
|||
'Rector\\TypeDeclaration\\TypeAnalyzer\\AlwaysStrictBoolExprAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictBoolExprAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\AlwaysStrictScalarExprAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictScalarExprAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\GenericClassStringTypeNormalizer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/TypeAnalyzer/GenericClassStringTypeNormalizer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\PropertyFetchTypeAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/TypeAnalyzer/PropertyFetchTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\ReturnStrictTypeAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/TypeAnalyzer/ReturnStrictTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeAnalyzer\\StrictReturnClassConstReturnTypeAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/TypeAnalyzer/StrictReturnClassConstReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\TypeInferer\\AssignToPropertyTypeInferer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/TypeInferer/AssignToPropertyTypeInferer.php',
|
||||
|
@ -3086,9 +3087,9 @@ class ComposerStaticInit0a672635d29f42a014258712107ce131
|
|||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit0a672635d29f42a014258712107ce131::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit0a672635d29f42a014258712107ce131::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit0a672635d29f42a014258712107ce131::$classMap;
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit6ed8c1e889d5a966c6689f7b3517e8f3::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit6ed8c1e889d5a966c6689f7b3517e8f3::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit6ed8c1e889d5a966c6689f7b3517e8f3::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue