From 348456e6b0b3b8f0448280c461e25cd0ecd2c756 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 10 Jan 2025 11:36:09 +0000 Subject: [PATCH] Updated Rector to commit fe8e48de8cc6c962430abab1b1766c05dd12309e https://github.com/rectorphp/rector-src/commit/fe8e48de8cc6c962430abab1b1766c05dd12309e [TypeDeclaration] Skip unset by trait on TypedPropertyFromStrictConstructorRector (#6664) --- src/Application/VersionResolver.php | 4 ++-- src/NodeAnalyzer/PropertyFetchAnalyzer.php | 24 ++++++++++++++++--- src/NodeManipulator/PropertyManipulator.php | 26 +++++++-------------- src/NodeNestingScope/ContextAnalyzer.php | 19 +++++++++++++++ 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index 1773ae7c3612..88548f6b7f95 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -19,12 +19,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = '8da1bfe2590771077da7ccd297f5df245d3e55c1'; + public const PACKAGE_VERSION = 'fe8e48de8cc6c962430abab1b1766c05dd12309e'; /** * @api * @var string */ - public const RELEASE_DATE = '2025-01-09 21:26:38'; + public const RELEASE_DATE = '2025-01-10 18:33:46'; /** * @var int */ diff --git a/src/NodeAnalyzer/PropertyFetchAnalyzer.php b/src/NodeAnalyzer/PropertyFetchAnalyzer.php index 0322c664ef02..b24402a2957a 100644 --- a/src/NodeAnalyzer/PropertyFetchAnalyzer.php +++ b/src/NodeAnalyzer/PropertyFetchAnalyzer.php @@ -20,8 +20,10 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Type\ObjectType; use PHPStan\Type\ThisType; +use Rector\DeadCode\NodeAnalyzer\PropertyWriteonlyAnalyzer; use Rector\Enum\ObjectReference; use Rector\NodeNameResolver\NodeNameResolver; +use Rector\NodeNestingScope\ContextAnalyzer; use Rector\NodeTypeResolver\NodeTypeResolver; use Rector\PhpParser\AstResolver; use Rector\PhpParser\Node\BetterNodeFinder; @@ -49,17 +51,27 @@ final class PropertyFetchAnalyzer * @readonly */ private ReflectionResolver $reflectionResolver; + /** + * @readonly + */ + private ContextAnalyzer $contextAnalyzer; + /** + * @readonly + */ + private PropertyWriteonlyAnalyzer $propertyWriteonlyAnalyzer; /** * @var string */ private const THIS = 'this'; - public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, AstResolver $astResolver, NodeTypeResolver $nodeTypeResolver, ReflectionResolver $reflectionResolver) + public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, AstResolver $astResolver, NodeTypeResolver $nodeTypeResolver, ReflectionResolver $reflectionResolver, ContextAnalyzer $contextAnalyzer, PropertyWriteonlyAnalyzer $propertyWriteonlyAnalyzer) { $this->nodeNameResolver = $nodeNameResolver; $this->betterNodeFinder = $betterNodeFinder; $this->astResolver = $astResolver; $this->nodeTypeResolver = $nodeTypeResolver; $this->reflectionResolver = $reflectionResolver; + $this->contextAnalyzer = $contextAnalyzer; + $this->propertyWriteonlyAnalyzer = $propertyWriteonlyAnalyzer; } public function isLocalPropertyFetch(Node $node) : bool { @@ -102,10 +114,16 @@ public function containsWrittenPropertyFetchName(Trait_ $trait, string $property return \true; } return (bool) $this->betterNodeFinder->findFirst($trait, function (Node $node) use($propertyName) : bool { - if (!$node instanceof Assign) { + if (!$this->isLocalPropertyFetchName($node, $propertyName)) { return \false; } - return $this->isLocalPropertyFetchName($node->var, $propertyName); + /** + * @var PropertyFetch|StaticPropertyFetch|NullsafePropertyFetch $node + */ + if ($this->contextAnalyzer->isChangeableContext($node)) { + return \true; + } + return $this->propertyWriteonlyAnalyzer->arePropertyFetchesExclusivelyBeingAssignedTo([$node]); }); } /** diff --git a/src/NodeManipulator/PropertyManipulator.php b/src/NodeManipulator/PropertyManipulator.php index 8c3a4cb4d20c..e825c92c1541 100644 --- a/src/NodeManipulator/PropertyManipulator.php +++ b/src/NodeManipulator/PropertyManipulator.php @@ -19,6 +19,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\NodeAnalyzer\PropertyFetchAnalyzer; use Rector\NodeNameResolver\NodeNameResolver; +use Rector\NodeNestingScope\ContextAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer; @@ -78,11 +79,15 @@ final class PropertyManipulator * @readonly */ private PropertyFetchAnalyzer $propertyFetchAnalyzer; + /** + * @readonly + */ + private ContextAnalyzer $contextAnalyzer; /** * @var string[]|class-string[] */ private const ALLOWED_NOT_READONLY_CLASS_ANNOTATIONS = ['ApiPlatform\\Core\\Annotation\\ApiResource', 'ApiPlatform\\Metadata\\ApiResource', 'Doctrine\\ORM\\Mapping\\Entity', 'Doctrine\\ORM\\Mapping\\Table', 'Doctrine\\ORM\\Mapping\\MappedSuperclass', 'Doctrine\\ORM\\Mapping\\Embeddable']; - public function __construct(\Rector\NodeManipulator\AssignManipulator $assignManipulator, BetterNodeFinder $betterNodeFinder, PhpDocInfoFactory $phpDocInfoFactory, PropertyFetchFinder $propertyFetchFinder, NodeNameResolver $nodeNameResolver, PhpAttributeAnalyzer $phpAttributeAnalyzer, NodeTypeResolver $nodeTypeResolver, PromotedPropertyResolver $promotedPropertyResolver, ConstructorAssignDetector $constructorAssignDetector, AstResolver $astResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer) + public function __construct(\Rector\NodeManipulator\AssignManipulator $assignManipulator, BetterNodeFinder $betterNodeFinder, PhpDocInfoFactory $phpDocInfoFactory, PropertyFetchFinder $propertyFetchFinder, NodeNameResolver $nodeNameResolver, PhpAttributeAnalyzer $phpAttributeAnalyzer, NodeTypeResolver $nodeTypeResolver, PromotedPropertyResolver $promotedPropertyResolver, ConstructorAssignDetector $constructorAssignDetector, AstResolver $astResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer, ContextAnalyzer $contextAnalyzer) { $this->assignManipulator = $assignManipulator; $this->betterNodeFinder = $betterNodeFinder; @@ -95,6 +100,7 @@ public function __construct(\Rector\NodeManipulator\AssignManipulator $assignMan $this->constructorAssignDetector = $constructorAssignDetector; $this->astResolver = $astResolver; $this->propertyFetchAnalyzer = $propertyFetchAnalyzer; + $this->contextAnalyzer = $contextAnalyzer; } /** * @param \PhpParser\Node\Stmt\Property|\PhpParser\Node\Param $propertyOrParam @@ -108,7 +114,7 @@ public function isPropertyChangeableExceptConstructor(Class_ $class, $propertyOr $propertyFetches = $this->propertyFetchFinder->findPrivatePropertyFetches($class, $propertyOrParam, $scope); $classMethod = $class->getMethod(MethodName::CONSTRUCT); foreach ($propertyFetches as $propertyFetch) { - if ($this->isChangeableContext($propertyFetch)) { + if ($this->contextAnalyzer->isChangeableContext($propertyFetch)) { return \true; } // skip for constructor? it is allowed to set value in constructor method @@ -192,22 +198,6 @@ private function isPropertyAssignedOnlyInConstructor(Class_ $class, string $prop } return $this->constructorAssignDetector->isPropertyAssigned($class, $propertyName); } - /** - * @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch $propertyFetch - */ - private function isChangeableContext($propertyFetch) : bool - { - if ($propertyFetch->getAttribute(AttributeKey::IS_UNSET_VAR, \false)) { - return \true; - } - if ($propertyFetch->getAttribute(AttributeKey::INSIDE_ARRAY_DIM_FETCH, \false)) { - return \true; - } - if ($propertyFetch->getAttribute(AttributeKey::IS_USED_AS_ARG_BY_REF_VALUE, \false) === \true) { - return \true; - } - return $propertyFetch->getAttribute(AttributeKey::IS_INCREMENT_OR_DECREMENT, \false) === \true; - } private function hasAllowedNotReadonlyAnnotationOrAttribute(PhpDocInfo $phpDocInfo, Class_ $class) : bool { if ($phpDocInfo->hasByAnnotationClasses(self::ALLOWED_NOT_READONLY_CLASS_ANNOTATIONS)) { diff --git a/src/NodeNestingScope/ContextAnalyzer.php b/src/NodeNestingScope/ContextAnalyzer.php index a795ff3bded4..1a046c8aa96c 100644 --- a/src/NodeNestingScope/ContextAnalyzer.php +++ b/src/NodeNestingScope/ContextAnalyzer.php @@ -4,6 +4,9 @@ namespace Rector\NodeNestingScope; use PhpParser\Node; +use PhpParser\Node\Expr\NullsafePropertyFetch; +use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Expr\StaticPropertyFetch; use Rector\NodeTypeResolver\Node\AttributeKey; final class ContextAnalyzer { @@ -21,4 +24,20 @@ public function isInIf(Node $node) : bool { return $node->getAttribute(AttributeKey::IS_IN_IF) === \true; } + /** + * @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch|\PhpParser\Node\Expr\NullsafePropertyFetch $propertyFetch + */ + public function isChangeableContext($propertyFetch) : bool + { + if ($propertyFetch->getAttribute(AttributeKey::IS_UNSET_VAR, \false)) { + return \true; + } + if ($propertyFetch->getAttribute(AttributeKey::INSIDE_ARRAY_DIM_FETCH, \false)) { + return \true; + } + if ($propertyFetch->getAttribute(AttributeKey::IS_USED_AS_ARG_BY_REF_VALUE, \false) === \true) { + return \true; + } + return $propertyFetch->getAttribute(AttributeKey::IS_INCREMENT_OR_DECREMENT, \false) === \true; + } }