mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-30 16:00:52 +00:00
[DoctrineCodeQuality] Add ImproveDoctrineCollectionDocTypeInEntityRector (#4442)
Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
parent
055040f8e8
commit
e845d7cea8
5
.github/workflows/rector.yaml
vendored
5
.github/workflows/rector.yaml
vendored
|
@ -12,11 +12,6 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
actions:
|
||||
-
|
||||
name: Rector CI
|
||||
install: composer install --no-progress --ansi
|
||||
run: composer rector-ci
|
||||
|
||||
-
|
||||
name: Rector without Dev Dependencies
|
||||
install: composer install --no-progress --ansi --no-dev
|
||||
|
|
|
@ -9,6 +9,7 @@ use Rector\DoctrineCodeQuality\Rector\ClassMethod\MakeEntityDateTimePropertyDate
|
|||
use Rector\DoctrineCodeQuality\Rector\ClassMethod\MakeEntitySetterNullabilityInSyncWithPropertyRector;
|
||||
use Rector\DoctrineCodeQuality\Rector\Property\ChangeBigIntEntityPropertyToIntTypeRector;
|
||||
use Rector\DoctrineCodeQuality\Rector\Property\CorrectDefaultTypesOnEntityPropertyRector;
|
||||
use Rector\DoctrineCodeQuality\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
|
@ -20,4 +21,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
$services->set(MoveCurrentDateTimeDefaultInEntityToConstructorRector::class);
|
||||
$services->set(CorrectDefaultTypesOnEntityPropertyRector::class);
|
||||
$services->set(ChangeBigIntEntityPropertyToIntTypeRector::class);
|
||||
$services->set(ImproveDoctrineCollectionDocTypeInEntityRector::class);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# All 593 Rectors Overview
|
||||
# All 595 Rectors Overview
|
||||
|
||||
- [Projects](#projects)
|
||||
---
|
||||
|
@ -10,11 +10,11 @@
|
|||
- [CakePHP](#cakephp) (6)
|
||||
- [CodeQuality](#codequality) (59)
|
||||
- [CodingStyle](#codingstyle) (33)
|
||||
- [DeadCode](#deadcode) (40)
|
||||
- [DeadCode](#deadcode) (41)
|
||||
- [Decouple](#decouple) (1)
|
||||
- [Defluent](#defluent) (8)
|
||||
- [Doctrine](#doctrine) (17)
|
||||
- [DoctrineCodeQuality](#doctrinecodequality) (8)
|
||||
- [DoctrineCodeQuality](#doctrinecodequality) (9)
|
||||
- [DoctrineGedmoToKnplabs](#doctrinegedmotoknplabs) (7)
|
||||
- [DowngradePhp71](#downgradephp71) (3)
|
||||
- [DowngradePhp72](#downgradephp72) (2)
|
||||
|
@ -2983,6 +2983,28 @@ Remove empty method calls not required by parents
|
|||
|
||||
<br><br>
|
||||
|
||||
### `RemoveEmptyMethodCallRector`
|
||||
|
||||
- class: [`Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector`](/rules/dead-code/src/Rector/MethodCall/RemoveEmptyMethodCallRector.php)
|
||||
- [test fixtures](/rules/dead-code/tests/Rector/MethodCall/RemoveEmptyMethodCallRector/Fixture)
|
||||
|
||||
Remove empty method call
|
||||
|
||||
```diff
|
||||
class SomeClass
|
||||
{
|
||||
public function callThis()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
-$some = new SomeClass();
|
||||
-$some->callThis();
|
||||
+$some = new SomeClass();
|
||||
```
|
||||
|
||||
<br><br>
|
||||
|
||||
### `RemoveNullPropertyInitializationRector`
|
||||
|
||||
- class: [`Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRector`](/rules/dead-code/src/Rector/PropertyProperty/RemoveNullPropertyInitializationRector.php)
|
||||
|
@ -4287,6 +4309,33 @@ Change default value types to match Doctrine annotation type
|
|||
|
||||
<br><br>
|
||||
|
||||
### `ImproveDoctrineCollectionDocTypeInEntityRector`
|
||||
|
||||
- class: [`Rector\DoctrineCodeQuality\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector`](/rules/doctrine-code-quality/src/Rector/Property/ImproveDoctrineCollectionDocTypeInEntityRector.php)
|
||||
- [test fixtures](/rules/doctrine-code-quality/tests/Rector/Property/ImproveDoctrineCollectionDocTypeInEntityRector/Fixture)
|
||||
|
||||
Improve @var, @param and @return types for Doctrine collections to make them useful both for PHPStan and PHPStorm
|
||||
|
||||
```diff
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class SomeClass
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
- * @var Collection|Trainer[]
|
||||
+ * @var Collection<int, Training>|Trainer[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
```
|
||||
|
||||
<br><br>
|
||||
|
||||
### `InitializeDefaultEntityCollectionRector`
|
||||
|
||||
- class: [`Rector\DoctrineCodeQuality\Rector\Class_\InitializeDefaultEntityCollectionRector`](/rules/doctrine-code-quality/src/Rector/Class_/InitializeDefaultEntityCollectionRector.php)
|
||||
|
@ -5034,13 +5083,17 @@ Convert the list reference assignment to its equivalent PHP 7.2 code
|
|||
- $array = [1, 2, 3];
|
||||
- list($a, &$b) = $array;
|
||||
+ $array = [1, 2];
|
||||
+ list($a, $b) = $array;
|
||||
+ list($a) = $array;
|
||||
+ $b =& $array[1];
|
||||
|
||||
- [&$c, $d, &$e] = $array;
|
||||
+ [$c, $d, $e] = $array;
|
||||
+ $c =& $array[0];
|
||||
+ $e =& $array[2];
|
||||
|
||||
- list(&$a, &$b) = $array;
|
||||
+ $a =& $array[0];
|
||||
+ $b =& $array[1];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -5082,8 +5135,7 @@ Add missing param to `array_merge` and `array_merge_recursive`
|
|||
```diff
|
||||
class SomeClass
|
||||
{
|
||||
- public function run()
|
||||
+ public function run()
|
||||
public function run()
|
||||
{
|
||||
- array_merge();
|
||||
- array_merge_recursive();
|
||||
|
|
|
@ -13,6 +13,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
|
|||
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareParamTagValueNode;
|
||||
|
@ -33,6 +34,7 @@ use Rector\PhpAttribute\Contract\PhpAttributableTagNodeInterface;
|
|||
use Rector\PHPStan\Type\FullyQualifiedObjectType;
|
||||
use Rector\PHPStan\Type\ShortenedObjectType;
|
||||
use Rector\StaticTypeMapper\StaticTypeMapper;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* @see \Rector\BetterPhpDocParser\Tests\PhpDocInfo\PhpDocInfo\PhpDocInfoTest
|
||||
|
@ -152,7 +154,7 @@ final class PhpDocInfo
|
|||
return count($this->tokens);
|
||||
}
|
||||
|
||||
public function getVarTagValue(): ?VarTagValueNode
|
||||
public function getVarTagValueNode(): ?VarTagValueNode
|
||||
{
|
||||
return $this->phpDocNode->getVarTagValues()[0] ?? null;
|
||||
}
|
||||
|
@ -212,7 +214,7 @@ final class PhpDocInfo
|
|||
|
||||
public function getVarType(): Type
|
||||
{
|
||||
return $this->getTypeOrMixed($this->getVarTagValue());
|
||||
return $this->getTypeOrMixed($this->getVarTagValueNode());
|
||||
}
|
||||
|
||||
public function getReturnType(): Type
|
||||
|
@ -370,8 +372,13 @@ final class PhpDocInfo
|
|||
return $this->tokens === [];
|
||||
}
|
||||
|
||||
public function changeParamType(Type $type, Param $param, string $paramName): void
|
||||
/**
|
||||
* @param Type|TypeNode $type
|
||||
*/
|
||||
public function changeParamType($type, Param $param, string $paramName): void
|
||||
{
|
||||
Assert::isAnyOf($type, [Type::class, TypeNode::class]);
|
||||
|
||||
$this->phpDocTypeChanger->changeParamType($this, $type, $param, $paramName);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Rector\BetterPhpDocParser\PhpDocManipulator;
|
||||
|
||||
use PhpParser\Node\Param;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Type\Constant\ConstantArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\NeverType;
|
||||
|
@ -18,6 +19,7 @@ use Rector\Core\Exception\ShouldNotHappenException;
|
|||
use Rector\NodeTypeResolver\PHPStan\TypeComparator;
|
||||
use Rector\StaticTypeMapper\StaticTypeMapper;
|
||||
use Rector\TypeDeclaration\PhpDocParser\ParamPhpDocNodeFactory;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class PhpDocTypeChanger
|
||||
{
|
||||
|
@ -75,7 +77,7 @@ final class PhpDocTypeChanger
|
|||
// override existing type
|
||||
$newPHPStanPhpDocType = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
|
||||
|
||||
$currentVarTagValueNode = $phpDocInfo->getVarTagValue();
|
||||
$currentVarTagValueNode = $phpDocInfo->getVarTagValueNode();
|
||||
if ($currentVarTagValueNode !== null) {
|
||||
// only change type
|
||||
$currentVarTagValueNode->type = $newPHPStanPhpDocType;
|
||||
|
@ -113,17 +115,26 @@ final class PhpDocTypeChanger
|
|||
$this->notifyChange();
|
||||
}
|
||||
|
||||
public function changeParamType(PhpDocInfo $phpDocInfo, Type $type, Param $param, string $paramName): void
|
||||
/**
|
||||
* @param Type|TypeNode $type
|
||||
*/
|
||||
public function changeParamType(PhpDocInfo $phpDocInfo, $type, Param $param, string $paramName): void
|
||||
{
|
||||
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($paramName);
|
||||
Assert::isAnyOf($type, [Type::class, TypeNode::class]);
|
||||
|
||||
$phpDocType = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($type);
|
||||
if (! $type instanceof TypeNode) {
|
||||
$phpDocType = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($type);
|
||||
} else {
|
||||
$phpDocType = $type;
|
||||
}
|
||||
|
||||
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($paramName);
|
||||
|
||||
// override existing type
|
||||
if ($paramTagValueNode !== null) {
|
||||
$paramTagValueNode->type = $phpDocType;
|
||||
} else {
|
||||
$paramTagValueNode = $this->paramPhpDocNodeFactory->create($type, $param);
|
||||
$paramTagValueNode = $this->paramPhpDocNodeFactory->create($phpDocType, $param);
|
||||
$phpDocInfo->addTagValueNode($paramTagValueNode);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ final class VarAnnotationManipulator
|
|||
$phpDocInfo = $this->resolvePhpDocInfo($node);
|
||||
|
||||
// already done
|
||||
if ($phpDocInfo->getVarTagValue() !== null) {
|
||||
if ($phpDocInfo->getVarTagValueNode() !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ final class ReadWritePropertyAnalyzer
|
|||
return $this->isArrayDimFetchRead($parent);
|
||||
}
|
||||
|
||||
return ! $this->assignManipulator->isNodeLeftPartOfAssign($node);
|
||||
return ! $this->assignManipulator->isLeftPartOfAssign($node);
|
||||
}
|
||||
|
||||
private function unwrapPostPreIncDec(Node $node): Node
|
||||
|
@ -93,7 +93,7 @@ final class ReadWritePropertyAnalyzer
|
|||
throw new MissingParentNodeException();
|
||||
}
|
||||
|
||||
if (! $this->assignManipulator->isNodeLeftPartOfAssign($arrayDimFetch)) {
|
||||
if (! $this->assignManipulator->isLeftPartOfAssign($arrayDimFetch)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,6 @@ final class ReadWritePropertyAnalyzer
|
|||
return true;
|
||||
}
|
||||
|
||||
return ! $this->assignManipulator->isNodeLeftPartOfAssign($arrayDimFetch);
|
||||
return ! $this->assignManipulator->isLeftPartOfAssign($arrayDimFetch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -209,6 +209,15 @@ final class RectorRecipe
|
|||
*/
|
||||
public function setPackage(string $package): void
|
||||
{
|
||||
if (is_file($package)) {
|
||||
$message = sprintf(
|
||||
'The "%s()" method only accepts package name, file path "%s" given',
|
||||
__METHOD__,
|
||||
$package
|
||||
);
|
||||
throw new ShouldNotHappenException($message);
|
||||
}
|
||||
|
||||
$this->package = $package;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,10 @@ namespace Rector\DoctrineCodeQuality\NodeAnalyzer;
|
|||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
|
||||
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\OneToManyTagValueNode;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class ColumnPropertyAnalyzer
|
||||
final class DoctrinePropertyAnalyzer
|
||||
{
|
||||
public function matchDoctrineColumnTagValueNode(Property $property): ?ColumnTagValueNode
|
||||
{
|
||||
|
@ -21,4 +22,15 @@ final class ColumnPropertyAnalyzer
|
|||
|
||||
return $phpDocInfo->getByType(ColumnTagValueNode::class);
|
||||
}
|
||||
|
||||
public function matchDoctrineOneToManyTagValueNode(Property $property): ?OneToManyTagValueNode
|
||||
{
|
||||
/** @var PhpDocInfo|null $phpDocInfo */
|
||||
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if ($phpDocInfo === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $phpDocInfo->getByType(OneToManyTagValueNode::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\PhpDoc;
|
||||
|
||||
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareArrayTypeNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareFullyQualifiedIdentifierTypeNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareIdentifierTypeNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareUnionTypeNode;
|
||||
|
||||
final class CollectionTypeFactory
|
||||
{
|
||||
public function createFromIdentifierType(IdentifierTypeNode $identifierTypeNode): AttributeAwareUnionTypeNode
|
||||
{
|
||||
$genericTypeNode = $this->createGenericTypeNode($identifierTypeNode);
|
||||
|
||||
return new AttributeAwareUnionTypeNode([
|
||||
$genericTypeNode,
|
||||
new AttributeAwareArrayTypeNode($identifierTypeNode),
|
||||
]);
|
||||
}
|
||||
|
||||
private function createGenericTypeNode(IdentifierTypeNode $identifierTypeNode): GenericTypeNode
|
||||
{
|
||||
$genericTypesNodes = [new AttributeAwareIdentifierTypeNode('int'), $identifierTypeNode];
|
||||
|
||||
return new GenericTypeNode(new AttributeAwareFullyQualifiedIdentifierTypeNode(
|
||||
'Doctrine\Common\Collections\Collection'
|
||||
), $genericTypesNodes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\PhpDoc;
|
||||
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareIdentifierTypeNode;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\OneToManyTagValueNode;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class CollectionTypeResolver
|
||||
{
|
||||
public function resolveFromType(TypeNode $typeNode): ?IdentifierTypeNode
|
||||
{
|
||||
if ($typeNode instanceof UnionTypeNode) {
|
||||
foreach ($typeNode->types as $unionedTypeNode) {
|
||||
if ($this->resolveFromType($unionedTypeNode) !== null) {
|
||||
return $this->resolveFromType($unionedTypeNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($typeNode instanceof ArrayTypeNode && $typeNode->type instanceof IdentifierTypeNode) {
|
||||
return $typeNode->type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function resolveFromOneToManyProperty(Property $property): ?IdentifierTypeNode
|
||||
{
|
||||
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if (! $phpDocInfo instanceof PhpDocInfo) {
|
||||
return null;
|
||||
}
|
||||
/** @var OneToManyTagValueNode|null $oneToManyTagValueNode */
|
||||
$oneToManyTagValueNode = $phpDocInfo->getByType(OneToManyTagValueNode::class);
|
||||
if ($oneToManyTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$fullyQualifiedTargetEntity = $oneToManyTagValueNode->getFullyQualifiedTargetEntity();
|
||||
if ($fullyQualifiedTargetEntity === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
return new AttributeAwareIdentifierTypeNode($fullyQualifiedTargetEntity);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\PhpDoc;
|
||||
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\DoctrineCodeQuality\NodeAnalyzer\DoctrinePropertyAnalyzer;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class CollectionVarTagValueNodeResolver
|
||||
{
|
||||
/**
|
||||
* @var DoctrinePropertyAnalyzer
|
||||
*/
|
||||
private $doctrinePropertyAnalyzer;
|
||||
|
||||
public function __construct(DoctrinePropertyAnalyzer $doctrinePropertyAnalyzer)
|
||||
{
|
||||
$this->doctrinePropertyAnalyzer = $doctrinePropertyAnalyzer;
|
||||
}
|
||||
|
||||
public function resolve(Property $property): ?VarTagValueNode
|
||||
{
|
||||
$doctrineOneToManyTagValueNode = $this->doctrinePropertyAnalyzer->matchDoctrineOneToManyTagValueNode($property);
|
||||
if ($doctrineOneToManyTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if (! $phpDocInfo instanceof PhpDocInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $phpDocInfo->getVarTagValueNode();
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
|||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\DoctrineCodeQuality\NodeAnalyzer\ColumnPropertyAnalyzer;
|
||||
use Rector\DoctrineCodeQuality\NodeAnalyzer\DoctrinePropertyAnalyzer;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockClassRenamer;
|
||||
|
||||
|
@ -28,9 +28,9 @@ use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockClassRenamer;
|
|||
final class ChangeBigIntEntityPropertyToIntTypeRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ColumnPropertyAnalyzer
|
||||
* @var DoctrinePropertyAnalyzer
|
||||
*/
|
||||
private $columnPropertyAnalyzer;
|
||||
private $doctrinePropertyAnalyzer;
|
||||
|
||||
/**
|
||||
* @var DocBlockClassRenamer
|
||||
|
@ -38,10 +38,10 @@ final class ChangeBigIntEntityPropertyToIntTypeRector extends AbstractRector
|
|||
private $docBlockClassRenamer;
|
||||
|
||||
public function __construct(
|
||||
ColumnPropertyAnalyzer $columnPropertyAnalyzer,
|
||||
DoctrinePropertyAnalyzer $doctrinePropertyAnalyzer,
|
||||
DocBlockClassRenamer $docBlockClassRenamer
|
||||
) {
|
||||
$this->columnPropertyAnalyzer = $columnPropertyAnalyzer;
|
||||
$this->doctrinePropertyAnalyzer = $doctrinePropertyAnalyzer;
|
||||
$this->docBlockClassRenamer = $docBlockClassRenamer;
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$columnTagValueNode = $this->columnPropertyAnalyzer->matchDoctrineColumnTagValueNode($node);
|
||||
$columnTagValueNode = $this->doctrinePropertyAnalyzer->matchDoctrineColumnTagValueNode($node);
|
||||
if ($columnTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$attributeAwareVarTagValueNode = $phpDocInfo->getVarTagValue();
|
||||
$attributeAwareVarTagValueNode = $phpDocInfo->getVarTagValueNode();
|
||||
if ($attributeAwareVarTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use Rector\Core\Exception\NotImplementedYetException;
|
|||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\DoctrineCodeQuality\NodeAnalyzer\ColumnPropertyAnalyzer;
|
||||
use Rector\DoctrineCodeQuality\NodeAnalyzer\DoctrinePropertyAnalyzer;
|
||||
|
||||
/**
|
||||
* @sponsor Thanks https://www.luzanky.cz/ for sponsoring this rule
|
||||
|
@ -24,13 +24,13 @@ use Rector\DoctrineCodeQuality\NodeAnalyzer\ColumnPropertyAnalyzer;
|
|||
final class CorrectDefaultTypesOnEntityPropertyRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ColumnPropertyAnalyzer
|
||||
* @var DoctrinePropertyAnalyzer
|
||||
*/
|
||||
private $columnPropertyAnalyzer;
|
||||
private $doctrinePropertyAnalyzer;
|
||||
|
||||
public function __construct(ColumnPropertyAnalyzer $columnPropertyAnalyzer)
|
||||
public function __construct(DoctrinePropertyAnalyzer $doctrinePropertyAnalyzer)
|
||||
{
|
||||
$this->columnPropertyAnalyzer = $columnPropertyAnalyzer;
|
||||
$this->doctrinePropertyAnalyzer = $doctrinePropertyAnalyzer;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
|
@ -84,7 +84,7 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$columnTagValueNode = $this->columnPropertyAnalyzer->matchDoctrineColumnTagValueNode($node);
|
||||
$columnTagValueNode = $this->doctrinePropertyAnalyzer->matchDoctrineColumnTagValueNode($node);
|
||||
if ($columnTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Rector\Property;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareVarTagValueNode;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\BetterPhpDocParser\PhpDocNode\Doctrine\Property_\OneToManyTagValueNode;
|
||||
use Rector\Core\PhpParser\Node\Manipulator\AssignManipulator;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\DoctrineCodeQuality\PhpDoc\CollectionTypeFactory;
|
||||
use Rector\DoctrineCodeQuality\PhpDoc\CollectionTypeResolver;
|
||||
use Rector\DoctrineCodeQuality\PhpDoc\CollectionVarTagValueNodeResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
/**
|
||||
* @see \Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\ImproveDoctrineCollectionDocTypeInEntityRectorTest
|
||||
*/
|
||||
final class ImproveDoctrineCollectionDocTypeInEntityRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var CollectionTypeFactory
|
||||
*/
|
||||
private $collectionTypeFactory;
|
||||
|
||||
/**
|
||||
* @var AssignManipulator
|
||||
*/
|
||||
private $assignManipulator;
|
||||
|
||||
/**
|
||||
* @var CollectionTypeResolver
|
||||
*/
|
||||
private $collectionTypeResolver;
|
||||
|
||||
/**
|
||||
* @var CollectionVarTagValueNodeResolver
|
||||
*/
|
||||
private $collectionVarTagValueNodeResolver;
|
||||
|
||||
public function __construct(
|
||||
CollectionTypeFactory $collectionTypeFactory,
|
||||
AssignManipulator $assignManipulator,
|
||||
CollectionTypeResolver $collectionTypeResolver,
|
||||
CollectionVarTagValueNodeResolver $collectionVarTagValueNodeResolver
|
||||
) {
|
||||
$this->collectionTypeFactory = $collectionTypeFactory;
|
||||
$this->assignManipulator = $assignManipulator;
|
||||
$this->collectionTypeResolver = $collectionTypeResolver;
|
||||
$this->collectionVarTagValueNodeResolver = $collectionVarTagValueNodeResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Improve @var, @param and @return types for Doctrine collections to make them useful both for PHPStan and PHPStorm',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class SomeClass
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var Collection|Trainer[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class SomeClass
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var Collection<int, Training>|Trainer[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Property::class, ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Property|ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($node instanceof Property) {
|
||||
return $this->refactorProperty($node);
|
||||
}
|
||||
|
||||
if ($node instanceof ClassMethod) {
|
||||
return $this->refactorClassMethod($node);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function refactorProperty(Property $property): ?Property
|
||||
{
|
||||
if (! $this->hasNodeTagValueNode($property, OneToManyTagValueNode::class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// @todo make an own local property on enter node?
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
|
||||
$attributeAwareVarTagValueNode = $this->collectionVarTagValueNodeResolver->resolve($property);
|
||||
if ($attributeAwareVarTagValueNode !== null) {
|
||||
$collectionObjectType = $this->collectionTypeResolver->resolveFromType(
|
||||
$attributeAwareVarTagValueNode->type
|
||||
);
|
||||
if ($collectionObjectType === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$attributeAwareVarTagValueNode->type = $this->collectionTypeFactory->createFromIdentifierType(
|
||||
$collectionObjectType
|
||||
);
|
||||
} else {
|
||||
$collectionObjectType = $this->collectionTypeResolver->resolveFromOneToManyProperty($property);
|
||||
if ($collectionObjectType === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$attributeAwareUnionTypeNode = $this->collectionTypeFactory->createFromIdentifierType(
|
||||
$collectionObjectType
|
||||
);
|
||||
$attributeAwareVarTagValueNode = new AttributeAwareVarTagValueNode($attributeAwareUnionTypeNode, '', '');
|
||||
$phpDocInfo->addTagValueNode($attributeAwareVarTagValueNode);
|
||||
}
|
||||
|
||||
return $property;
|
||||
}
|
||||
|
||||
private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod
|
||||
{
|
||||
if (! $this->isInDoctrineEntityClass($classMethod)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $classMethod->isPublic()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$collectionObjectType = $this->resolveCollectionSetterAssignType($classMethod);
|
||||
if ($collectionObjectType === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($classMethod->params) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $classMethod->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
|
||||
$param = $classMethod->params[0];
|
||||
$parameterName = $this->getName($param);
|
||||
$phpDocInfo->changeParamType($collectionObjectType, $param, $parameterName);
|
||||
|
||||
return $classMethod;
|
||||
}
|
||||
|
||||
private function hasNodeTagValueNode(Node $node, string $tagValueNodeClass): bool
|
||||
{
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if (! $phpDocInfo instanceof PhpDocInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $phpDocInfo->hasByType($tagValueNodeClass);
|
||||
}
|
||||
|
||||
private function resolveCollectionSetterAssignType(ClassMethod $classMethod): ?TypeNode
|
||||
{
|
||||
$propertyFetches = $this->assignManipulator->resolveAssignsToLocalPropertyFetches($classMethod);
|
||||
if (count($propertyFetches) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$property = $this->matchPropertyFetchToClassProperty($propertyFetches[0]);
|
||||
if ($property === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$varTagValueNode = $this->collectionVarTagValueNodeResolver->resolve($property);
|
||||
if ($varTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $varTagValueNode->type;
|
||||
}
|
||||
|
||||
private function matchPropertyFetchToClassProperty(PropertyFetch $propertyFetch): ?Property
|
||||
{
|
||||
$propertyName = $this->getName($propertyFetch);
|
||||
if ($propertyName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$classLike = $propertyFetch->getAttribute(AttributeKey::CLASS_NODE);
|
||||
if (! $classLike instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $classLike->getProperty($propertyName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class NoVar
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class NoVar
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class ParamWithoutArray
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
*/
|
||||
private $trainings = [];
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*/
|
||||
public function setTrainings($collection): void
|
||||
{
|
||||
$this->trainings = $collection;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class ParamWithoutArray
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
|
||||
/**
|
||||
* @param \Doctrine\Common\Collections\Collection<int, Training>|Training[] $collection
|
||||
*/
|
||||
public function setTrainings($collection): void
|
||||
{
|
||||
$this->trainings = $collection;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class VarSomeClass
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var Collection<int, string>|Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class VarSomeClass
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class VarWithoutArray
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class VarWithoutArray
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class VarWithoutCollection
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector\Fixture;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class VarWithoutCollection
|
||||
{
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Training::class, mappedBy="trainer")
|
||||
* @var \Doctrine\Common\Collections\Collection<int, Training>|Training[]
|
||||
*/
|
||||
private $trainings = [];
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DoctrineCodeQuality\Tests\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\DoctrineCodeQuality\Rector\Property\ImproveDoctrineCollectionDocTypeInEntityRector;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class ImproveDoctrineCollectionDocTypeInEntityRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return ImproveDoctrineCollectionDocTypeInEntityRector::class;
|
||||
}
|
||||
}
|
|
@ -143,7 +143,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
// it needs @var tag as well, to get the type
|
||||
if ($phpDocInfo->getVarTagValue() !== null) {
|
||||
if ($phpDocInfo->getVarTagValueNode() !== null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$attributeAwareVarTagValueNode = $phpDocInfo->getVarTagValue();
|
||||
$attributeAwareVarTagValueNode = $phpDocInfo->getVarTagValueNode();
|
||||
if ($attributeAwareVarTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\PHPUnit\Composer;
|
||||
|
||||
use Nette\Utils\Arrays;
|
||||
use Nette\Utils\Json;
|
||||
use Rector\Core\Testing\PHPUnit\StaticPHPUnitEnvironment;
|
||||
use Symplify\SmartFileSystem\SmartFileSystem;
|
||||
|
@ -32,7 +33,7 @@ final class ComposerAutoloadedDirectoryProvider
|
|||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @return string[]|mixed[]
|
||||
*/
|
||||
public function provide(): array
|
||||
{
|
||||
|
@ -49,10 +50,10 @@ final class ComposerAutoloadedDirectoryProvider
|
|||
}
|
||||
|
||||
$sectionDirectories = $this->collectDirectoriesFromAutoload($composerJson[$autoloadSection]);
|
||||
$autoloadDirectories = array_merge($autoloadDirectories, $sectionDirectories);
|
||||
$autoloadDirectories[] = $sectionDirectories;
|
||||
}
|
||||
|
||||
return $autoloadDirectories;
|
||||
return Arrays::flatten($autoloadDirectories);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,9 +49,7 @@ final class PHPUnitTestCaseClassesProvider
|
|||
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/tests_add_see_rector_tests');
|
||||
|
||||
$directories = $this->composerAutoloadedDirectoryProvider->provide();
|
||||
foreach ($directories as $directory) {
|
||||
$robotLoader->addDirectory($directory);
|
||||
}
|
||||
$robotLoader->addDirectory(...$directories);
|
||||
|
||||
$robotLoader->acceptFiles = ['*Test.php'];
|
||||
$robotLoader->ignoreDirs[] = '*Expected*';
|
||||
|
|
|
@ -110,7 +110,7 @@ CODE_SAMPLE
|
|||
|
||||
private function getVarDocVariableName(PhpDocInfo $phpDocInfo): ?string
|
||||
{
|
||||
$attributeAwareVarTagValueNode = $phpDocInfo->getVarTagValue();
|
||||
$attributeAwareVarTagValueNode = $phpDocInfo->getVarTagValueNode();
|
||||
if ($attributeAwareVarTagValueNode === null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ CODE_SAMPLE
|
|||
|
||||
private function refactorAlreadyCreatedNode(Node $node, PhpDocInfo $phpDocInfo, Variable $variable): ?Node
|
||||
{
|
||||
$varTagValue = $phpDocInfo->getVarTagValue();
|
||||
$varTagValue = $phpDocInfo->getVarTagValueNode();
|
||||
if ($varTagValue === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
|
|
@ -5,10 +5,9 @@ declare(strict_types=1);
|
|||
namespace Rector\TypeDeclaration\PhpDocParser;
|
||||
|
||||
use PhpParser\Node\Param;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareParamTagValueNode;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\StaticTypeMapper\StaticTypeMapper;
|
||||
|
||||
final class ParamPhpDocNodeFactory
|
||||
{
|
||||
|
@ -17,21 +16,13 @@ final class ParamPhpDocNodeFactory
|
|||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
/**
|
||||
* @var StaticTypeMapper
|
||||
*/
|
||||
private $staticTypeMapper;
|
||||
|
||||
public function __construct(NodeNameResolver $nodeNameResolver, StaticTypeMapper $staticTypeMapper)
|
||||
public function __construct(NodeNameResolver $nodeNameResolver)
|
||||
{
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->staticTypeMapper = $staticTypeMapper;
|
||||
}
|
||||
|
||||
public function create(Type $type, Param $param): AttributeAwareParamTagValueNode
|
||||
public function create(TypeNode $typeNode, Param $param): AttributeAwareParamTagValueNode
|
||||
{
|
||||
$typeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($type);
|
||||
|
||||
return new AttributeAwareParamTagValueNode(
|
||||
$typeNode,
|
||||
$param->variadic,
|
||||
|
|
|
@ -100,10 +100,7 @@ final class AdditionalAutoloader
|
|||
}
|
||||
// last argument is workaround: https://github.com/nette/robot-loader/issues/12
|
||||
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_rector_robot_loader');
|
||||
|
||||
foreach ($directories as $autoloadDirectory) {
|
||||
$robotLoader->addDirectory($autoloadDirectory);
|
||||
}
|
||||
$robotLoader->addDirectory(...$directories);
|
||||
|
||||
$robotLoader->register();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,11 @@ use PhpParser\Node\Expr\PostDec;
|
|||
use PhpParser\Node\Expr\PostInc;
|
||||
use PhpParser\Node\Expr\PreDec;
|
||||
use PhpParser\Node\Expr\PreInc;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -42,10 +46,26 @@ final class AssignManipulator
|
|||
*/
|
||||
private $betterStandardPrinter;
|
||||
|
||||
public function __construct(BetterStandardPrinter $betterStandardPrinter, NodeNameResolver $nodeNameResolver)
|
||||
{
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
/**
|
||||
* @var PropertyFetchAnalyzer
|
||||
*/
|
||||
private $propertyFetchAnalyzer;
|
||||
|
||||
public function __construct(
|
||||
BetterStandardPrinter $betterStandardPrinter,
|
||||
NodeNameResolver $nodeNameResolver,
|
||||
BetterNodeFinder $betterNodeFinder,
|
||||
PropertyFetchAnalyzer $propertyFetchAnalyzer
|
||||
) {
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +85,7 @@ final class AssignManipulator
|
|||
return $this->nodeNameResolver->isName($assign->expr, 'each');
|
||||
}
|
||||
|
||||
public function isNodeLeftPartOfAssign(Node $node): bool
|
||||
public function isLeftPartOfAssign(Node $node): bool
|
||||
{
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentNode instanceof Assign && $parentNode->var === $node) {
|
||||
|
@ -116,6 +136,20 @@ final class AssignManipulator
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PropertyFetch[]
|
||||
*/
|
||||
public function resolveAssignsToLocalPropertyFetches(FunctionLike $functionLike): array
|
||||
{
|
||||
return $this->betterNodeFinder->find($functionLike->getStmts(), function (Node $node): bool {
|
||||
if (! $this->propertyFetchAnalyzer->isLocalPropertyFetch($node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isLeftPartOfAssign($node);
|
||||
});
|
||||
}
|
||||
|
||||
private function isValueModifyingNode(Node $node): bool
|
||||
{
|
||||
foreach (self::MODIFYING_NODES as $modifyingNode) {
|
||||
|
|
|
@ -193,6 +193,6 @@ final class PropertyManipulator
|
|||
}
|
||||
}
|
||||
|
||||
return $this->assignManipulator->isNodeLeftPartOfAssign($node);
|
||||
return $this->assignManipulator->isLeftPartOfAssign($node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ final class VariableManipulator
|
|||
return false;
|
||||
}
|
||||
|
||||
if (! $this->assignManipulator->isNodeLeftPartOfAssign($variableUsage)) {
|
||||
if (! $this->assignManipulator->isLeftPartOfAssign($variableUsage)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,13 +83,13 @@ final class RectorsFinder
|
|||
private function findClassesInDirectoriesByName(array $directories, string $name): array
|
||||
{
|
||||
$robotLoader = new RobotLoader();
|
||||
foreach ($directories as $directory) {
|
||||
$robotLoader->addDirectory($directory);
|
||||
}
|
||||
$robotLoader->addDirectory(...$directories);
|
||||
|
||||
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_rector_finder');
|
||||
|
||||
$robotLoader->acceptFiles = [$name];
|
||||
$robotLoader->excludeDirectory(__DIR__ . '/../../../packages/rector-generator/tests');
|
||||
|
||||
$robotLoader->rebuild();
|
||||
|
||||
$classNames = [];
|
||||
|
|
|
@ -34,12 +34,12 @@ final class NodeClassFinder
|
|||
private function findClassesByNamePatternInDirectories(string $namePattern, array $directories): array
|
||||
{
|
||||
$robotLoader = new RobotLoader();
|
||||
foreach ($directories as $directory) {
|
||||
$robotLoader->addDirectory($directory);
|
||||
}
|
||||
$robotLoader->addDirectory(...$directories);
|
||||
|
||||
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_phpdoc_parser_ast');
|
||||
|
||||
$robotLoader->acceptFiles = [$namePattern];
|
||||
|
||||
$robotLoader->rebuild();
|
||||
|
||||
$indexedClasses = $robotLoader->getIndexedClasses();
|
||||
|
|
Loading…
Reference in New Issue
Block a user