diff --git a/config/set/type-declaration-docblocks.php b/config/set/type-declaration-docblocks.php index cdb3ec5375c..0db20f012bf 100644 --- a/config/set/type-declaration-docblocks.php +++ b/config/set/type-declaration-docblocks.php @@ -7,6 +7,7 @@ use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnDocblockForScalarArrayFromAssignsRector; use Rector\TypeDeclarationDocblocks\Rector\Class_\AddReturnDocblockDataProviderRector; use Rector\TypeDeclarationDocblocks\Rector\Class_\ClassMethodArrayDocblockParamFromLocalCallsRector; +use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarArrayFromGetterReturnRector; use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarArrayFromPropertyDefaultsRector; use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarFromParamDocblockInConstructorRector; use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockFromDataProviderRector; @@ -24,6 +25,7 @@ // property var DocblockVarFromParamDocblockInConstructorRector::class, DocblockVarArrayFromPropertyDefaultsRector::class, + DocblockVarArrayFromGetterReturnRector::class, // param AddParamArrayDocblockFromDimFetchAccessRector::class, diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/DocblockVarArrayFromGetterReturnRectorTest.php b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/DocblockVarArrayFromGetterReturnRectorTest.php new file mode 100644 index 00000000000..561e9534cf5 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/DocblockVarArrayFromGetterReturnRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/skip_missing_array.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/skip_missing_array.php.inc new file mode 100644 index 00000000000..ee526455ecd --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/skip_missing_array.php.inc @@ -0,0 +1,16 @@ +names; + } +} diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/skip_missing_return_on_getter.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/skip_missing_return_on_getter.php.inc new file mode 100644 index 00000000000..21008eba801 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/skip_missing_return_on_getter.php.inc @@ -0,0 +1,13 @@ +names; + } +} diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/some_class.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/some_class.php.inc new file mode 100644 index 00000000000..9f642d49ea0 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/Fixture/some_class.php.inc @@ -0,0 +1,40 @@ +names; + } +} + +?> +----- +names; + } +} + +?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/config/configured_rule.php b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/config/configured_rule.php new file mode 100644 index 00000000000..42e44ef285a --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(DocblockVarArrayFromGetterReturnRector::class); +}; diff --git a/rules/TypeDeclarationDocblocks/NodeFinder/PropertyGetterFinder.php b/rules/TypeDeclarationDocblocks/NodeFinder/PropertyGetterFinder.php new file mode 100644 index 00000000000..c8c55a57d43 --- /dev/null +++ b/rules/TypeDeclarationDocblocks/NodeFinder/PropertyGetterFinder.php @@ -0,0 +1,69 @@ +nodeNameResolver->getName($property); + foreach ($class->getMethods() as $classMethod) { + if ($classMethod->isMagic()) { + continue; + } + + if ($classMethod->isAbstract()) { + continue; + } + + if ($classMethod->stmts === null) { + continue; + } + + if (count($classMethod->stmts) !== 1) { + continue; + } + + $onlyStmt = $classMethod->stmts[0]; + if (! $onlyStmt instanceof Return_) { + continue; + } + + if (! $onlyStmt->expr instanceof PropertyFetch) { + continue; + } + + $propertyFetch = $onlyStmt->expr; + if (! $propertyFetch->var instanceof Variable) { + continue; + } + + if (! $this->nodeNameResolver->isName($propertyFetch->var, 'this')) { + continue; + } + + if (! $this->nodeNameResolver->isName($propertyFetch->name, $propertyName)) { + continue; + } + + return $classMethod; + } + + return null; + } +} diff --git a/rules/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector.php b/rules/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector.php new file mode 100644 index 00000000000..ccad236cbbb --- /dev/null +++ b/rules/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromGetterReturnRector.php @@ -0,0 +1,131 @@ +items; + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class SomeClass +{ + /** + * @var int[] + */ + private array $items; + + /** + * @return int[] + */ + public function getItems(): array + { + return $this->items; + } +} +CODE_SAMPLE + ), + ]); + } + + /** + * @param Class_ $node + */ + public function refactor(Node $node): ?Node + { + $hasChanged = false; + + foreach ($node->getProperties() as $property) { + // property type must be known + if (! $property->type instanceof Identifier) { + continue; + } + + if (! $this->isName($property->type, 'array')) { + continue; + } + + if (count($property->props) > 1) { + continue; + } + + $propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property); + + // type is already known, skip it + if ($propertyPhpDocInfo->getVarTagValueNode() instanceof VarTagValueNode) { + continue; + } + + $propertyGetterMethod = $this->propertyGetterFinder->find($property, $node); + if (! $propertyGetterMethod instanceof ClassMethod) { + continue; + } + + $classMethodDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($propertyGetterMethod); + $returnTagValueNode = $classMethodDocInfo->getReturnTagValue(); + if (! $returnTagValueNode instanceof ReturnTagValueNode) { + continue; + } + + $varTagValeNode = new VarTagValueNode($returnTagValueNode->type, '', ''); + + // find matching getter and its @return docblock + $propertyPhpDocInfo->addTagValueNode($varTagValeNode); + $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($property); + + $hasChanged = true; + } + + if (! $hasChanged) { + return null; + } + + return $node; + } +}