From 5eaa1bf93c9eae012ccd992f8ce2dcdebdf6a049 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 2 Sep 2026 16:18:40 +0200 Subject: [PATCH] [TypeDeclarationDocblocks] Skip keyed and direct property assigns in AddVarArrayDocblockFromDimFetchAssignRector The rule inferred @var only from bare appends ($this->prop[] = ...). When the same property is also written with a keyed dim assign ($this->prop['error'] = 'text') or a direct assign, those value types were ignored and the resulting @var was too narrow, rejecting them. Skip such properties instead. --- .../Fixture/skip_keyed_assign.php.inc | 18 +++++++++ .../NodeFinder/ArrayDimFetchFinder.php | 39 +++++++++++++++++++ ...rArrayDocblockFromDimFetchAssignRector.php | 5 +++ 3 files changed, 62 insertions(+) create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector/Fixture/skip_keyed_assign.php.inc diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector/Fixture/skip_keyed_assign.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector/Fixture/skip_keyed_assign.php.inc new file mode 100644 index 00000000000..1d7874d6680 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector/Fixture/skip_keyed_assign.php.inc @@ -0,0 +1,18 @@ +response[] = [ + 'name' => 'John', + ]; + + $this->response['error'] = 'some error'; + $this->response['done'] = true; + } +} diff --git a/rules/TypeDeclarationDocblocks/NodeFinder/ArrayDimFetchFinder.php b/rules/TypeDeclarationDocblocks/NodeFinder/ArrayDimFetchFinder.php index a4047bed05b..6dabc8ed762 100644 --- a/rules/TypeDeclarationDocblocks/NodeFinder/ArrayDimFetchFinder.php +++ b/rules/TypeDeclarationDocblocks/NodeFinder/ArrayDimFetchFinder.php @@ -90,6 +90,36 @@ public function findDimFetchAssignToPropertyName(Class_ $class, string $variable return $exprs; } + /** + * Any write to the property other than a bare append $this->someProperty[] = ..., + * i.e. a keyed dim assign $this->someProperty['key'] = ... or a direct $this->someProperty = ... + */ + public function hasNonAppendAssignToPropertyName(Class_ $class, string $variableName): bool + { + $assigns = $this->betterNodeFinder->findInstancesOfScoped($class->getMethods(), Assign::class); + + foreach ($assigns as $assign) { + if ($assign->var instanceof PropertyFetch && $this->isThisPropertyNamed($assign->var, $variableName)) { + return true; + } + + if (! $assign->var instanceof ArrayDimFetch) { + continue; + } + + // bare append, already covered by findDimFetchAssignToPropertyName() + if (! $assign->var->dim instanceof Expr) { + continue; + } + + if ($assign->var->var instanceof PropertyFetch && $this->isThisPropertyNamed($assign->var->var, $variableName)) { + return true; + } + } + + return false; + } + /** * @return ArrayDimFetch[] */ @@ -106,6 +136,15 @@ public function findByVariableName(Node $node, string $variableName): array }); } + private function isThisPropertyNamed(PropertyFetch $propertyFetch, string $propertyName): bool + { + if (! $this->nodeNameResolver->isName($propertyFetch->var, 'this')) { + return false; + } + + return $this->nodeNameResolver->isName($propertyFetch->name, $propertyName); + } + /** * @return ArrayDimFetch[] */ diff --git a/rules/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector.php b/rules/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector.php index 0c742963f3c..902aca74a73 100644 --- a/rules/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/Class_/AddVarArrayDocblockFromDimFetchAssignRector.php @@ -101,6 +101,11 @@ public function refactor(Node $node): ?Node $propertyName = $this->getName($property); + // a keyed dim assign ($this->prop['x'] = ...) or a direct assign carries a value type this rule does not read from bare appends; skip to avoid a too-narrow @var + if ($this->arrayDimFetchFinder->hasNonAppendAssignToPropertyName($node, $propertyName)) { + continue; + } + $assignedExprs = $this->arrayDimFetchFinder->findDimFetchAssignToPropertyName($node, $propertyName); $assignedExprTypes = [];