Print only changed docblocks 🎉🎉🎉 (#5251)

This commit is contained in:
Tomas Votruba 2021-01-20 17:17:59 +01:00 committed by GitHub
parent 85e7f7fa2c
commit 87494ce3a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 536 additions and 598 deletions

View File

@ -448,6 +448,10 @@ final class PhpDocInfo
public function hasChanged(): bool
{
if ($this->isNewNode()) {
return true;
}
return $this->hasChanged;
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocManipulator;
use PhpParser\Node;
use PhpParser\Node\Param;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\MixedType;
@ -13,9 +12,6 @@ use PHPStan\Type\Type;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareReturnTagValueNode;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareVarTagValueNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\PHPStan\TypeComparator;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\TypeDeclaration\PhpDocParser\ParamPhpDocNodeFactory;
@ -32,16 +28,6 @@ final class PhpDocTypeChanger
*/
private $staticTypeMapper;
/**
* @var RectorChangeCollector
*/
private $rectorChangeCollector;
/**
* @var CurrentNodeProvider
*/
private $currentNodeProvider;
/**
* @var ParamPhpDocNodeFactory
*/
@ -50,14 +36,10 @@ final class PhpDocTypeChanger
public function __construct(
StaticTypeMapper $staticTypeMapper,
TypeComparator $typeComparator,
RectorChangeCollector $rectorChangeCollector,
CurrentNodeProvider $currentNodeProvider,
ParamPhpDocNodeFactory $paramPhpDocNodeFactory
) {
$this->typeComparator = $typeComparator;
$this->staticTypeMapper = $staticTypeMapper;
$this->rectorChangeCollector = $rectorChangeCollector;
$this->currentNodeProvider = $currentNodeProvider;
$this->paramPhpDocNodeFactory = $paramPhpDocNodeFactory;
}
@ -80,14 +62,12 @@ final class PhpDocTypeChanger
if ($currentVarTagValueNode !== null) {
// only change type
$currentVarTagValueNode->type = $newPHPStanPhpDocType;
$phpDocInfo->markAsChanged();
} else {
// add completely new one
$attributeAwareVarTagValueNode = new AttributeAwareVarTagValueNode($newPHPStanPhpDocType, '', '');
$phpDocInfo->addTagValueNode($attributeAwareVarTagValueNode);
}
// notify about node change
$this->notifyChange();
}
public function changeReturnType(PhpDocInfo $phpDocInfo, Type $newType): void
@ -104,14 +84,12 @@ final class PhpDocTypeChanger
if ($currentReturnTagValueNode !== null) {
// only change type
$currentReturnTagValueNode->type = $newPHPStanPhpDocType;
$phpDocInfo->markAsChanged();
} else {
// add completely new one
$attributeAwareReturnTagValueNode = new AttributeAwareReturnTagValueNode($newPHPStanPhpDocType, '');
$phpDocInfo->addTagValueNode($attributeAwareReturnTagValueNode);
}
// notify about node change
$this->notifyChange();
}
public function changeParamType(PhpDocInfo $phpDocInfo, Type $newType, Param $param, string $paramName): void
@ -132,22 +110,10 @@ final class PhpDocTypeChanger
}
$paramTagValueNode->type = $phpDocType;
$phpDocInfo->markAsChanged();
} else {
$paramTagValueNode = $this->paramPhpDocNodeFactory->create($phpDocType, $param);
$phpDocInfo->addTagValueNode($paramTagValueNode);
}
// notify about node change
$this->notifyChange();
}
private function notifyChange(): void
{
$node = $this->currentNodeProvider->getNode();
if (! $node instanceof Node) {
throw new ShouldNotHappenException();
}
$this->rectorChangeCollector->notifyNodeFileInfo($node);
}
}

View File

@ -35,5 +35,7 @@ final class PropertyDocBlockManipulator
}
$paramTagValueNode->parameterName = '$' . $renameValueObject->getExpectedName();
$phpDocInfo->markAsChanged();
}
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Rector\BetterPhpDocParser\Printer;
use Nette\Utils\Strings;
final class DocBlockInliner
{
/**
* @var string
* @see https://regex101.com/r/Mjb0qi/1
*/
private const NEWLINE_CLOSING_DOC_REGEX = "#\n \*\/$#";
/**
* @var string
* @see https://regex101.com/r/U5OUV4/2
*/
private const NEWLINE_MIDDLE_DOC_REGEX = "#\n \* #";
public function inline(string $docContent): string
{
$docContent = Strings::replace($docContent, self::NEWLINE_MIDDLE_DOC_REGEX, ' ');
return Strings::replace($docContent, self::NEWLINE_CLOSING_DOC_REGEX, ' */');
}
}

View File

@ -111,16 +111,33 @@ final class PhpDocInfoPrinter
*/
private $emptyPhpDocDetector;
/**
* @var DocBlockInliner
*/
private $docBlockInliner;
public function __construct(
EmptyPhpDocDetector $emptyPhpDocDetector,
MultilineSpaceFormatPreserver $multilineSpaceFormatPreserver,
OriginalSpacingRestorer $originalSpacingRestorer,
SpacePatternFactory $spacePatternFactory
SpacePatternFactory $spacePatternFactory,
DocBlockInliner $docBlockInliner
) {
$this->originalSpacingRestorer = $originalSpacingRestorer;
$this->multilineSpaceFormatPreserver = $multilineSpaceFormatPreserver;
$this->spacePatternFactory = $spacePatternFactory;
$this->emptyPhpDocDetector = $emptyPhpDocDetector;
$this->docBlockInliner = $docBlockInliner;
}
public function printNew(PhpDocInfo $phpDocInfo): string
{
$docContent = (string) $phpDocInfo->getPhpDocNode();
if (! $phpDocInfo->isSingleLine()) {
return $docContent;
}
return $this->docBlockInliner->inline($docContent);
}
/**

View File

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace Rector\Comments\NodeDocBlock;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\Printer\PhpDocInfoPrinter;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class DocBlockUpdater
{
/**
* @var string
* @see https://regex101.com/r/VdaVGL/1
*/
public const SPACE_OR_ASTERISK_REGEX = '#(\s|\*)+#';
/**
* @var PhpDocInfoPrinter
*/
private $phpDocInfoPrinter;
public function __construct(PhpDocInfoPrinter $phpDocInfoPrinter)
{
$this->phpDocInfoPrinter = $phpDocInfoPrinter;
}
public function updateNodeWithPhpDocInfo(Node $node): void
{
// nothing to change? don't save it
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
if (! $phpDocInfo instanceof PhpDocInfo) {
return;
}
if (! $phpDocInfo->hasChanged()) {
return;
}
$phpDoc = $this->printPhpDocInfoToString($phpDocInfo);
// make sure, that many separated comments are not removed
if ($phpDoc === '') {
if (count($node->getComments()) > 1) {
foreach ($node->getComments() as $comment) {
$phpDoc .= $comment->getText() . PHP_EOL;
}
}
if ($phpDocInfo->getOriginalPhpDocNode()->children !== []) {
// all comments were removed → null
$node->setAttribute(AttributeKey::COMMENTS, null);
}
return;
}
// this is needed to remove duplicated // commentsAsText
$node->setDocComment(new Doc($phpDoc));
}
private function printPhpDocInfoToString(PhpDocInfo $phpDocInfo): string
{
if ($phpDocInfo->isNewNode()) {
return $this->phpDocInfoPrinter->printNew($phpDocInfo);
}
return $this->phpDocInfoPrinter->printFormatPreserving($phpDocInfo);
}
}

View File

@ -16,11 +16,6 @@ use Symplify\SimplePhpDocParser\PhpDocNodeTraverser;
final class DocBlockClassRenamer
{
/**
* @var bool
*/
private $hasNodeChanged = false;
/**
* @var StaticTypeMapper
*/
@ -56,11 +51,11 @@ final class DocBlockClassRenamer
Type $oldType,
Type $newType,
Node $phpParserNode
): bool {
): void {
$this->phpDocNodeTraverser->traverseWithCallable(
$phpDocInfo->getPhpDocNode(),
'',
function (PhpDocParserNode $node) use ($phpParserNode, $oldType, $newType): PhpDocParserNode {
function (PhpDocParserNode $node) use ($phpDocInfo, $phpParserNode, $oldType, $newType): PhpDocParserNode {
if (! $node instanceof IdentifierTypeNode) {
return $node;
}
@ -76,12 +71,10 @@ final class DocBlockClassRenamer
return $node;
}
$this->hasNodeChanged = true;
$phpDocInfo->markAsChanged();
return $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
}
);
return $this->hasNodeChanged;
}
}

View File

@ -1,163 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer;
use Nette\Utils\Strings;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\Printer\PhpDocInfoPrinter;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class DocBlockManipulator
{
/**
* @var string
* @see https://regex101.com/r/VdaVGL/1
*/
public const SPACE_OR_ASTERISK_REGEX = '#(\s|\*)+#';
/**
* @var string
* @see https://regex101.com/r/Mjb0qi/1
*/
private const NEWLINE_CLOSING_DOC_REGEX = "#\n \*\/$#";
/**
* @var string
* @see https://regex101.com/r/U5OUV4/2
*/
private const NEWLINE_MIDDLE_DOC_REGEX = "#\n \* #";
/**
* @var PhpDocInfoPrinter
*/
private $phpDocInfoPrinter;
/**
* @var DocBlockClassRenamer
*/
private $docBlockClassRenamer;
public function __construct(DocBlockClassRenamer $docBlockClassRenamer, PhpDocInfoPrinter $phpDocInfoPrinter)
{
$this->phpDocInfoPrinter = $phpDocInfoPrinter;
$this->docBlockClassRenamer = $docBlockClassRenamer;
}
public function changeType(PhpDocInfo $phpDocInfo, Node $node, Type $oldType, Type $newType): void
{
$this->docBlockClassRenamer->renamePhpDocType($phpDocInfo, $oldType, $newType, $node);
}
public function updateNodeWithPhpDocInfo(Node $node): void
{
// nothing to change
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
if (! $phpDocInfo instanceof PhpDocInfo) {
return;
}
$phpDoc = $this->printPhpDocInfoToString($phpDocInfo);
// make sure, that many separated comments are not removed
if ($phpDoc === '' && count($node->getComments()) > 1) {
foreach ($node->getComments() as $comment) {
$phpDoc .= $comment->getText() . PHP_EOL;
}
}
if ($phpDoc === '') {
if ($phpDocInfo->getOriginalPhpDocNode()->children !== []) {
// all comments were removed → null
$node->setAttribute(AttributeKey::COMMENTS, null);
}
return;
}
// no change, don't save it
// this is needed to prevent short classes override with FQN with same value → people don't like that for some reason
if (! $this->haveDocCommentOrCommentsChanged($node, $phpDoc)) {
return;
}
// this is needed to remove duplicated // commentsAsText
$node->setDocComment(new Doc($phpDoc));
}
private function printPhpDocInfoToString(PhpDocInfo $phpDocInfo): string
{
// new node, needs to be reparsed
if ($phpDocInfo->isNewNode()) {
$docContent = (string) $phpDocInfo->getPhpDocNode();
if (! $phpDocInfo->isSingleLine()) {
return $docContent;
}
return $this->inlineDocContent($docContent);
}
return $this->phpDocInfoPrinter->printFormatPreserving($phpDocInfo);
}
private function haveDocCommentOrCommentsChanged(Node $node, string $phpDoc): bool
{
$docComment = $node->getDocComment();
if ($docComment !== null && $docComment->getText() === $phpDoc) {
return false;
}
$phpDoc = $this->completeSimpleCommentsToPhpDoc($node, $phpDoc);
if ($node->getComments() !== []) {
$commentsContent = implode(PHP_EOL, $node->getComments());
if ($this->removeSpacesAndAsterisks($commentsContent) === $this->removeSpacesAndAsterisks($phpDoc)) {
return false;
}
}
return true;
}
private function inlineDocContent(string $docContent): string
{
$docContent = Strings::replace($docContent, self::NEWLINE_MIDDLE_DOC_REGEX, ' ');
return Strings::replace($docContent, self::NEWLINE_CLOSING_DOC_REGEX, ' */');
}
/**
* add // comments to phpdoc (only has /**
*/
private function completeSimpleCommentsToPhpDoc(Node $node, string $phpDoc): string
{
$startComments = '';
foreach ($node->getComments() as $comment) {
// skip simple comments
if (Strings::startsWith($comment->getText(), '//')) {
continue;
}
if (Strings::startsWith($comment->getText(), '#')) {
continue;
}
$startComments .= $comment->getText() . PHP_EOL;
}
if ($startComments === '') {
return $phpDoc;
}
return $startComments . PHP_EOL . $phpDoc;
}
private function removeSpacesAndAsterisks(string $content): string
{
return Strings::replace($content, self::SPACE_OR_ASTERISK_REGEX, '');
}
}

View File

@ -18,11 +18,6 @@ use Symplify\SimplePhpDocParser\PhpDocNodeTraverser;
final class DocBlockNameImporter
{
/**
* @var bool
*/
private $hasPhpDocChanged = false;
/**
* @var PhpDocNodeTraverser
*/
@ -62,15 +57,13 @@ final class DocBlockNameImporter
$this->useNodesToAddCollector = $useNodesToAddCollector;
}
public function importNames(PhpDocInfo $phpDocInfo, Node $phpParserNode): bool
public function importNames(PhpDocInfo $phpDocInfo, Node $phpParserNode): void
{
$attributeAwarePhpDocNode = $phpDocInfo->getPhpDocNode();
$this->hasPhpDocChanged = false;
$this->phpDocNodeTraverser->traverseWithCallable($attributeAwarePhpDocNode, '', function (
PhpDocParserNode $docNode
) use ($phpParserNode): PhpDocParserNode {
) use ($phpDocInfo, $phpParserNode): PhpDocParserNode {
if (! $docNode instanceof IdentifierTypeNode) {
return $docNode;
}
@ -87,13 +80,12 @@ final class DocBlockNameImporter
return $docNode;
}
return $this->processFqnNameImport($phpParserNode, $docNode, $staticType);
return $this->processFqnNameImport($phpDocInfo, $phpParserNode, $docNode, $staticType);
});
return $this->hasPhpDocChanged;
}
private function processFqnNameImport(
PhpDocInfo $phpDocInfo,
Node $node,
IdentifierTypeNode $identifierTypeNode,
FullyQualifiedObjectType $fullyQualifiedObjectType
@ -109,7 +101,7 @@ final class DocBlockNameImporter
if ($this->useNodesToAddCollector->isShortImported($node, $fullyQualifiedObjectType)) {
if ($this->useNodesToAddCollector->isImportShortable($node, $fullyQualifiedObjectType)) {
$identifierTypeNode->name = $fullyQualifiedObjectType->getShortName();
$this->hasPhpDocChanged = true;
$phpDocInfo->markAsChanged();
}
return $identifierTypeNode;
@ -117,8 +109,8 @@ final class DocBlockNameImporter
$shortenedIdentifierTypeNode = new IdentifierTypeNode($fullyQualifiedObjectType->getShortName());
$this->hasPhpDocChanged = true;
$this->useNodesToAddCollector->addUseImport($node, $fullyQualifiedObjectType);
$phpDocInfo->markAsChanged();
return $shortenedIdentifierTypeNode;
}

View File

@ -43,7 +43,7 @@ final class PhpDocTypeRenamer
$this->phpDocNodeTraverser->traverseWithCallable($attributeAwarePhpDocNode, '', function (
PhpDocParserNode $node
) use ($pseudoNamespaceToNamespace, $phpParserNode): PhpDocParserNode {
) use ($pseudoNamespaceToNamespace, $phpParserNode, $phpDocInfo): PhpDocParserNode {
if (! $node instanceof TypeNode) {
return $node;
}
@ -62,6 +62,8 @@ final class PhpDocTypeRenamer
$slashedName = '\\' . Strings::replace($staticType->getClassName(), '#_#', '\\');
$node->name = $slashedName;
$phpDocInfo->markAsChanged();
return $node;
});
}

View File

@ -210,7 +210,7 @@ trait NodeCommandersTrait
}
}
protected function notifyNodeFileInfo(Node $node): void
private function notifyNodeFileInfo(Node $node): void
{
$this->rectorChangeCollector->notifyNodeFileInfo($node);
}

View File

@ -73,11 +73,7 @@ final class NameImportingPostRector extends AbstractPostRector
}
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
$hasChanged = $this->docBlockNameImporter->importNames($phpDocInfo, $node);
if (! $hasChanged) {
return null;
}
$this->docBlockNameImporter->importNames($phpDocInfo, $node);
return $node;
}

View File

@ -301,6 +301,7 @@ parameters:
- packages/better-php-doc-parser/src/Comment/CommentsMerger.php
- packages/node-type-resolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php
- rules/coding-style/src/Node/DocAliasResolver.php
- packages/comments/src/NodeDocBlock/DocBlockUpdater.php
- packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfoFactory.php
- packages/better-php-doc-parser/tests/PhpDocInfo/PhpDocInfoPrinter/AbstractPhpDocInfoPrinterTest.php

View File

@ -9,6 +9,7 @@ use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\PhpParser\Node\CustomNode\FileNode;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\FileSystemRector\ValueObject\MovedFileWithNodes;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -28,6 +29,16 @@ final class MoveEntitiesToEntityDirectoryRector extends AbstractRector
*/
private const ENTITY_PATH_REGEX = '#\bEntity\b#';
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Move entities to Entity namespace', [
@ -109,6 +120,6 @@ CODE_SAMPLE
return false;
}
return $this->isDoctrineEntityClass($class);
return $this->doctrineDocBlockResolver->isDoctrineEntityClass($class);
}
}

View File

@ -13,6 +13,7 @@ use PHPStan\Type\ObjectType;
use Rector\BetterPhpDocParser\Contract\Doctrine\DoctrineRelationTagValueNodeInterface;
use Rector\BetterPhpDocParser\Contract\Doctrine\InversedByNodeInterface;
use Rector\BetterPhpDocParser\Contract\Doctrine\MappedByNodeInterface;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Class_\EntityTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Class_\InheritanceTypeTagValueNode;
@ -94,9 +95,8 @@ final class DoctrineEntityManipulator
return $phpDocInfo->hasByTypes([InheritanceTypeTagValueNode::class, EntityTagValueNode::class]);
}
public function removeMappedByOrInversedByFromProperty(Property $property): void
public function removeMappedByOrInversedByFromProperty(PhpDocInfo $phpDocInfo): void
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$relationTagValueNode = $phpDocInfo->getByType(DoctrineRelationTagValueNodeInterface::class);
if ($relationTagValueNode instanceof MappedByNodeInterface && $relationTagValueNode->getMappedBy()) {
@ -111,6 +111,7 @@ final class DoctrineEntityManipulator
return;
}
$phpDocInfo->markAsChanged();
$relationTagValueNode->removeInversedBy();
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\DeadCode\FlowControl;
namespace Rector\DeadCode\NodeFinder;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;

View File

@ -7,12 +7,16 @@ namespace Rector\DeadCode\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Caching\Contract\Rector\ZeroCacheRectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Rector\AbstractRector;
use Rector\DeadCode\UnusedNodeResolver\UnusedClassResolver;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpAttribute\ValueObject\TagName;
use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @see \Rector\DeadCode\Tests\Rector\Class_\RemoveUnusedClassesRector\RemoveUnusedClassesRectorTest
@ -24,9 +28,17 @@ final class RemoveUnusedClassesRector extends AbstractRector implements ZeroCach
*/
private $unusedClassResolver;
public function __construct(UnusedClassResolver $unusedClassResolver)
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(
UnusedClassResolver $unusedClassResolver,
DoctrineDocBlockResolver $doctrineDocBlockResolver
) {
$this->unusedClassResolver = $unusedClassResolver;
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
@ -92,7 +104,12 @@ CODE_SAMPLE
if (StaticPHPUnitEnvironment::isPHPUnitRun()) {
$this->removeNode($node);
} else {
$this->removeFile($this->getFileInfo());
$smartFileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
if (! $smartFileInfo instanceof SmartFileInfo) {
throw new ShouldNotHappenException();
}
$this->removeFile($smartFileInfo);
}
return null;
@ -104,7 +121,7 @@ CODE_SAMPLE
return true;
}
if ($this->isDoctrineEntityClass($class)) {
if ($this->doctrineDocBlockResolver->isDoctrineEntityClass($class)) {
return true;
}

View File

@ -12,6 +12,7 @@ use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\Contract\Doctrine\DoctrineRelationTagValueNodeInterface;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\IdTagValueNode;
use Rector\Caching\Contract\Rector\ZeroCacheRectorInterface;
use Rector\Core\PhpParser\Node\Manipulator\ClassManipulator;
@ -187,7 +188,7 @@ CODE_SAMPLE
$this->removeNode($this->collectionByPropertyName[$propertyName]);
}
$this->removeInversedByOrMappedByOnRelatedProperty($property);
$this->removeInversedByOrMappedByOnRelatedProperty($phpDocInfo, $property);
}
return $class;
@ -228,14 +229,15 @@ CODE_SAMPLE
return $usedPropertyNames;
}
private function removeInversedByOrMappedByOnRelatedProperty(Property $property): void
private function removeInversedByOrMappedByOnRelatedProperty(PhpDocInfo $phpDocInfo, Property $property): void
{
$otherRelationProperty = $this->getOtherRelationProperty($property);
$otherRelationProperty = $this->getOtherRelationProperty($phpDocInfo, $property);
if (! $otherRelationProperty instanceof Property) {
return;
}
$this->doctrineEntityManipulator->removeMappedByOrInversedByFromProperty($otherRelationProperty);
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($otherRelationProperty);
$this->doctrineEntityManipulator->removeMappedByOrInversedByFromProperty($phpDocInfo);
}
private function isPropertyFetchAssignOfArrayCollection(PropertyFetch $propertyFetch): bool
@ -255,9 +257,8 @@ CODE_SAMPLE
return $this->isName($new->class, ArrayCollection::class);
}
private function getOtherRelationProperty(Property $property): ?Property
private function getOtherRelationProperty(PhpDocInfo $phpDocInfo, Property $property): ?Property
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$doctrineRelationTagValueNode = $phpDocInfo->getByType(DoctrineRelationTagValueNodeInterface::class);
if (! $doctrineRelationTagValueNode instanceof DoctrineRelationTagValueNodeInterface) {
return null;

View File

@ -10,8 +10,8 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\FunctionLike;
use Rector\Core\Context\ContextAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Rector\DeadCode\FlowControl\VariableUseFinder;
use Rector\DeadCode\NodeCollector\NodeByTypeAndPositionCollector;
use Rector\DeadCode\NodeFinder\VariableUseFinder;
use Rector\DeadCode\ValueObject\VariableNodeUse;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;

View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Rector\Defluent\NodeFactory;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class FluentMethodCallAsArgFactory
{
public function createFluentAsArg(MethodCall $methodCall, Variable $variable): MethodCall
{
/** @var Arg $parent */
$parent = $methodCall->getAttribute(AttributeKey::PARENT_NODE);
/** @var MethodCall $parentParent */
$parentParent = $parent->getAttribute(AttributeKey::PARENT_NODE);
$lastMethodCall = new MethodCall($parentParent->var, $parentParent->name);
$lastMethodCall->args[] = new Arg($variable);
return $lastMethodCall;
}
}

View File

@ -12,6 +12,8 @@ use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\Rector\Return_\DefluentReturnMethodCallRector;
use Rector\Defluent\ValueObject\AssignAndRootExprAndNodesToAdd;
use Rector\Defluent\ValueObject\FluentCallsKind;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\PackageBuilder\Php\TypeChecker;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -23,6 +25,16 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class FluentChainMethodCallToNormalMethodCallRector extends AbstractFluentChainMethodCallRector
{
/**
* @var TypeChecker
*/
private $typeChecker;
public function __construct(TypeChecker $typeChecker)
{
$this->typeChecker = $typeChecker;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
@ -88,6 +100,7 @@ CODE_SAMPLE
*/
private function isHandledByAnotherRule(MethodCall $methodCall): bool
{
return $this->hasParentTypes($methodCall, [Return_::class, Arg::class]);
$parent = $methodCall->getAttribute(AttributeKey::PARENT_NODE);
return $this->typeChecker->isInstanceOf($parent, [Return_::class, Arg::class]);
}
}

View File

@ -8,8 +8,8 @@ use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
use Rector\Defluent\NodeAnalyzer\NewFluentChainMethodCallNodeAnalyzer;
use Rector\Defluent\NodeFactory\FluentMethodCallAsArgFactory;
use Rector\Defluent\NodeFactory\VariableFromNewFactory;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\ValueObject\AssignAndRootExprAndNodesToAdd;
@ -35,12 +35,19 @@ final class InArgFluentChainMethodCallToStandaloneMethodCallRector extends Abstr
*/
private $variableFromNewFactory;
/**
* @var FluentMethodCallAsArgFactory
*/
private $fluentMethodCallAsArgFactory;
public function __construct(
NewFluentChainMethodCallNodeAnalyzer $newFluentChainMethodCallNodeAnalyzer,
VariableFromNewFactory $variableFromNewFactory
VariableFromNewFactory $variableFromNewFactory,
FluentMethodCallAsArgFactory $fluentMethodCallAsArgFactory
) {
$this->newFluentChainMethodCallNodeAnalyzer = $newFluentChainMethodCallNodeAnalyzer;
$this->variableFromNewFactory = $variableFromNewFactory;
$this->fluentMethodCallAsArgFactory = $fluentMethodCallAsArgFactory;
}
public function getRuleDefinition(): RuleDefinition
@ -95,14 +102,12 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (! $this->hasParentType($node, Arg::class)) {
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if (! $parent instanceof Arg) {
return null;
}
/** @var Arg $arg */
$arg = $node->getAttribute(AttributeKey::PARENT_NODE);
/** @var Node|null $parentMethodCall */
$parentMethodCall = $arg->getAttribute(AttributeKey::PARENT_NODE);
$parentMethodCall = $parent->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentMethodCall instanceof MethodCall) {
return null;
}
@ -139,29 +144,12 @@ CODE_SAMPLE
$nodesToAdd = $this->nonFluentChainMethodCallFactory->createFromNewAndRootMethodCall($new, $methodCall);
$newVariable = $this->variableFromNewFactory->create($new);
$nodesToAdd[] = $this->createFluentAsArg($methodCall, $newVariable);
$nodesToAdd[] = $this->fluentMethodCallAsArgFactory->createFluentAsArg($methodCall, $newVariable);
$this->addNodesBeforeNode($nodesToAdd, $methodCall);
$this->removeParentParent($methodCall);
}
/**
* @deprecated
* @todo extact to factory
*/
private function createFluentAsArg(MethodCall $methodCall, Variable $variable): MethodCall
{
/** @var Arg $parent */
$parent = $methodCall->getAttribute(AttributeKey::PARENT_NODE);
/** @var MethodCall $parentParent */
$parentParent = $parent->getAttribute(AttributeKey::PARENT_NODE);
$lastMethodCall = new MethodCall($parentParent->var, $parentParent->name);
$lastMethodCall->args[] = new Arg($variable);
return $lastMethodCall;
}
private function removeParentParent(MethodCall $methodCall): void
{
/** @var Arg $parent */

View File

@ -11,6 +11,8 @@ use PhpParser\Node\Stmt\Return_;
use Rector\Defluent\Rector\AbstractFluentChainMethodCallRector;
use Rector\Defluent\ValueObject\AssignAndRootExprAndNodesToAdd;
use Rector\Defluent\ValueObject\FluentCallsKind;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\PackageBuilder\Php\TypeChecker;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -23,6 +25,16 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class NewFluentChainMethodCallToNonFluentRector extends AbstractFluentChainMethodCallRector
{
/**
* @var TypeChecker
*/
private $typeChecker;
public function __construct(TypeChecker $typeChecker)
{
$this->typeChecker = $typeChecker;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
@ -58,7 +70,8 @@ CODE_SAMPLE
public function refactor(Node $node): ?Node
{
// handled by another rule
if ($this->hasParentTypes($node, [Return_::class, Arg::class])) {
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($this->typeChecker->isInstanceOf($parent, [Return_::class, Arg::class])) {
return null;
}

View File

@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeAnalyzer;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
final class ColumnDatetimePropertyAnalyzer
{
/**
* @var PhpDocInfoFactory
*/
private $phpDocInfoFactory;
public function __construct(PhpDocInfoFactory $phpDocInfoFactory)
{
$this->phpDocInfoFactory = $phpDocInfoFactory;
}
public function matchDateTimeColumnTagValueNodeInProperty(Property $property): ?ColumnTagValueNode
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$columnTagValueNode = $phpDocInfo->getByType(ColumnTagValueNode::class);
if (! $columnTagValueNode instanceof ColumnTagValueNode) {
return null;
}
/** @var ColumnTagValueNode $columnTagValueNode */
if ($columnTagValueNode->getType() !== 'datetime') {
return null;
}
return $columnTagValueNode;
}
}

View File

@ -4,36 +4,26 @@ declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\NodeManipulator;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode;
final class DoctrineItemDefaultValueManipulator
{
/**
* @var bool
*/
private $hasModifiedAnnotation = false;
/**
* @param string|bool|int $defaultValue
*/
public function remove(AbstractDoctrineTagValueNode $doctrineTagValueNode, string $item, $defaultValue): void
{
public function remove(
PhpDocInfo $phpDocInfo,
AbstractDoctrineTagValueNode $doctrineTagValueNode,
string $item,
$defaultValue
): void {
if (! $this->hasItemWithDefaultValue($doctrineTagValueNode, $item, $defaultValue)) {
return;
}
$this->hasModifiedAnnotation = true;
$doctrineTagValueNode->removeItem($item);
}
public function resetHasModifiedAnnotation(): void
{
$this->hasModifiedAnnotation = false;
}
public function hasModifiedAnnotation(): bool
{
return $this->hasModifiedAnnotation;
$phpDocInfo->markAsChanged();
}
/**

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\ManyToOneTagValueNode;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\DoctrineCodeQuality\NodeAnalyzer\SetterClassMethodAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -28,9 +29,17 @@ final class MakeEntitySetterNullabilityInSyncWithPropertyRector extends Abstract
*/
private $setterClassMethodAnalyzer;
public function __construct(SetterClassMethodAnalyzer $setterClassMethodAnalyzer)
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(
SetterClassMethodAnalyzer $setterClassMethodAnalyzer,
DoctrineDocBlockResolver $doctrineDocBlockResolver
) {
$this->setterClassMethodAnalyzer = $setterClassMethodAnalyzer;
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
@ -98,7 +107,7 @@ CODE_SAMPLE
public function refactor(Node $node): ?Node
{
// is setter in doctrine?
if (! $this->isInDoctrineEntityClass($node)) {
if (! $this->doctrineDocBlockResolver->isInDoctrineEntityClass($node)) {
return null;
}

View File

@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
use Rector\Core\Rector\AbstractRector;
use Rector\DoctrineCodeQuality\NodeAnalyzer\ColumnDatetimePropertyAnalyzer;
use Rector\DoctrineCodeQuality\NodeAnalyzer\ConstructorAssignPropertyAnalyzer;
use Rector\DoctrineCodeQuality\NodeFactory\ValueAssignFactory;
use Rector\DoctrineCodeQuality\NodeManipulator\ColumnDatetimePropertyManipulator;
@ -27,11 +26,6 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class MoveCurrentDateTimeDefaultInEntityToConstructorRector extends AbstractRector
{
/**
* @var ColumnDatetimePropertyAnalyzer
*/
private $columnDatetimePropertyAnalyzer;
/**
* @var ConstructorManipulator
*/
@ -53,13 +47,11 @@ final class MoveCurrentDateTimeDefaultInEntityToConstructorRector extends Abstra
private $constructorAssignPropertyAnalyzer;
public function __construct(
ColumnDatetimePropertyAnalyzer $columnDatetimePropertyAnalyzer,
ConstructorManipulator $constructorManipulator,
ValueAssignFactory $valueAssignFactory,
ColumnDatetimePropertyManipulator $columnDatetimePropertyManipulator,
ConstructorAssignPropertyAnalyzer $constructorAssignPropertyAnalyzer
) {
$this->columnDatetimePropertyAnalyzer = $columnDatetimePropertyAnalyzer;
$this->constructorManipulator = $constructorManipulator;
$this->valueAssignFactory = $valueAssignFactory;
$this->columnDatetimePropertyManipulator = $columnDatetimePropertyManipulator;
@ -138,14 +130,18 @@ CODE_SAMPLE
private function refactorProperty(Property $property, Class_ $class): ?Property
{
$columnTagValueNode = $this->columnDatetimePropertyAnalyzer->matchDateTimeColumnTagValueNodeInProperty(
$property
);
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$columnTagValueNode = $phpDocInfo->getByType(ColumnTagValueNode::class);
if (! $columnTagValueNode instanceof ColumnTagValueNode) {
return null;
}
/** @var ColumnTagValueNode $columnTagValueNode */
if ($columnTagValueNode->getType() !== 'datetime') {
return null;
}
$constructorAssign = $this->constructorAssignPropertyAnalyzer->resolveConstructorAssign($property);
// 0. already has default
@ -155,6 +151,7 @@ CODE_SAMPLE
// 1. remove default options from database level
$this->columnDatetimePropertyManipulator->removeDefaultOption($columnTagValueNode);
$phpDocInfo->markAsChanged();
// 2. remove default value
$this->refactorClass($class, $property);

View File

@ -72,15 +72,10 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
$this->doctrineItemDefaultValueManipulator->resetHasModifiedAnnotation();
if ($node instanceof Class_) {
$this->refactorClassAnnotations($node);
}
if (! $this->doctrineItemDefaultValueManipulator->hasModifiedAnnotation()) {
return null;
}
return $node;
}
@ -98,6 +93,6 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($entityTagValueNode, 'readOnly', false);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $entityTagValueNode, 'readOnly', false);
}
}

View File

@ -15,6 +15,7 @@ use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\OneToManyTagValueNode;
use Rector\Core\PhpParser\Node\Manipulator\AssignManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\DoctrineCodeQuality\PhpDoc\CollectionTypeFactory;
use Rector\DoctrineCodeQuality\PhpDoc\CollectionTypeResolver;
use Rector\DoctrineCodeQuality\PhpDoc\CollectionVarTagValueNodeResolver;
@ -53,18 +54,25 @@ final class ImproveDoctrineCollectionDocTypeInEntityRector extends AbstractRecto
*/
private $phpDocTypeChanger;
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(
CollectionTypeFactory $collectionTypeFactory,
AssignManipulator $assignManipulator,
CollectionTypeResolver $collectionTypeResolver,
CollectionVarTagValueNodeResolver $collectionVarTagValueNodeResolver,
PhpDocTypeChanger $phpDocTypeChanger
PhpDocTypeChanger $phpDocTypeChanger,
DoctrineDocBlockResolver $doctrineDocBlockResolver
) {
$this->collectionTypeFactory = $collectionTypeFactory;
$this->assignManipulator = $assignManipulator;
$this->collectionTypeResolver = $collectionTypeResolver;
$this->collectionVarTagValueNodeResolver = $collectionVarTagValueNodeResolver;
$this->phpDocTypeChanger = $phpDocTypeChanger;
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
@ -166,7 +174,7 @@ CODE_SAMPLE
private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod
{
if (! $this->isInDoctrineEntityClass($classMethod)) {
if (! $this->doctrineDocBlockResolver->isInDoctrineEntityClass($classMethod)) {
return null;
}

View File

@ -104,15 +104,10 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
$this->doctrineItemDefaultValueManipulator->resetHasModifiedAnnotation();
if ($node instanceof Property) {
$this->refactorPropertyAnnotations($node);
}
if (! $this->doctrineItemDefaultValueManipulator->hasModifiedAnnotation()) {
return null;
}
return $node;
}
@ -136,10 +131,10 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($columnTagValueNode, 'nullable', false);
$this->doctrineItemDefaultValueManipulator->remove($columnTagValueNode, 'unique', false);
$this->doctrineItemDefaultValueManipulator->remove($columnTagValueNode, 'precision', 0);
$this->doctrineItemDefaultValueManipulator->remove($columnTagValueNode, 'scale', 0);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $columnTagValueNode, 'nullable', false);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $columnTagValueNode, 'unique', false);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $columnTagValueNode, 'precision', 0);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $columnTagValueNode, 'scale', 0);
}
private function refactorGeneratedValueAnnotation(PhpDocInfo $phpDocInfo): void
@ -149,7 +144,12 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($generatedValueTagValueNode, 'strategy', 'AUTO');
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$generatedValueTagValueNode,
'strategy',
'AUTO'
);
}
private function refactorJoinColumnAnnotation(PhpDocInfo $phpDocInfo): void
@ -159,9 +159,14 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($joinColumnTagValueNode, 'nullable', true);
$this->doctrineItemDefaultValueManipulator->remove($joinColumnTagValueNode, 'referencedColumnName', 'id');
$this->doctrineItemDefaultValueManipulator->remove($joinColumnTagValueNode, 'unique', false);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $joinColumnTagValueNode, 'nullable', true);
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$joinColumnTagValueNode,
'referencedColumnName',
'id'
);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $joinColumnTagValueNode, 'unique', false);
}
private function refactorManyToManyAnnotation(PhpDocInfo $phpDocInfo): void
@ -171,8 +176,18 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($manyToManyTagValueNode, self::ORPHAN_REMOVAL, false);
$this->doctrineItemDefaultValueManipulator->remove($manyToManyTagValueNode, self::FETCH, self::LAZY);
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$manyToManyTagValueNode,
self::ORPHAN_REMOVAL,
false
);
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$manyToManyTagValueNode,
self::FETCH,
self::LAZY
);
}
private function refactorManyToOneAnnotation(PhpDocInfo $phpDocInfo): void
@ -182,7 +197,12 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($manyToOneTagValueNode, self::FETCH, self::LAZY);
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$manyToOneTagValueNode,
self::FETCH,
self::LAZY
);
}
private function refactorOneToManyAnnotation(PhpDocInfo $phpDocInfo): void
@ -192,8 +212,18 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($oneToManyTagValueNode, self::ORPHAN_REMOVAL, false);
$this->doctrineItemDefaultValueManipulator->remove($oneToManyTagValueNode, self::FETCH, self::LAZY);
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$oneToManyTagValueNode,
self::ORPHAN_REMOVAL,
false
);
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$oneToManyTagValueNode,
self::FETCH,
self::LAZY
);
}
private function refactorOneToOneAnnotation(PhpDocInfo $phpDocInfo): void
@ -203,7 +233,12 @@ CODE_SAMPLE
return;
}
$this->doctrineItemDefaultValueManipulator->remove($oneToOneTagValueNode, self::ORPHAN_REMOVAL, false);
$this->doctrineItemDefaultValueManipulator->remove($oneToOneTagValueNode, self::FETCH, self::LAZY);
$this->doctrineItemDefaultValueManipulator->remove(
$phpDocInfo,
$oneToOneTagValueNode,
self::ORPHAN_REMOVAL,
false
);
$this->doctrineItemDefaultValueManipulator->remove($phpDocInfo, $oneToOneTagValueNode, self::FETCH, self::LAZY);
}
}

View File

@ -1,49 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Doctrine\AbstractRector;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
trait DoctrineTrait
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
/**
* @required
*/
public function autowireDoctrineTrait(DoctrineDocBlockResolver $doctrineDocBlockResolver): void
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
protected function isDoctrineProperty(Property $property): bool
{
return $this->doctrineDocBlockResolver->isDoctrineProperty($property);
}
/**
* @param Class_|string $class
*/
protected function isDoctrineEntityClass($class): bool
{
return $this->doctrineDocBlockResolver->isDoctrineEntityClass($class);
}
protected function isInDoctrineEntityClass(Node $node): bool
{
return $this->doctrineDocBlockResolver->isInDoctrineEntityClass($node);
}
protected function getTargetEntity(Property $property): ?string
{
return $this->doctrineDocBlockResolver->getTargetEntity($property);
}
}

View File

@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\BetterPhpDocParser\Contract\Doctrine\DoctrineRelationTagValueNodeInterface;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Class_\EmbeddableTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Class_\EntityTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\IdTagValueNode;
@ -88,12 +87,6 @@ final class DoctrineDocBlockResolver
return $doctrineRelationTagValueNode->getTargetEntity();
}
public function isDoctrineProperty(Property $property): bool
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
return $phpDocInfo->hasByType(AbstractDoctrineTagValueNode::class);
}
public function isInDoctrineEntityClass(Node $node): bool
{
$classLike = $node->getAttribute(AttributeKey::CLASS_NODE);

View File

@ -9,6 +9,7 @@ use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassMethod;
use Ramsey\Uuid\UuidInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -19,6 +20,16 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class ChangeGetIdTypeToUuidRector extends AbstractRector
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
@ -72,7 +83,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInDoctrineEntityClass($node)) {
if (! $this->doctrineDocBlockResolver->isInDoctrineEntityClass($node)) {
return null;
}

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassMethod;
use Ramsey\Uuid\UuidInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -20,6 +21,16 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class ChangeSetIdTypeToUuidRector extends AbstractRector
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
@ -77,7 +88,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInDoctrineEntityClass($node)) {
if (! $this->doctrineDocBlockResolver->isInDoctrineEntityClass($node)) {
return null;
}

View File

@ -19,6 +19,7 @@ use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\OneToOne
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\Collector\UuidMigrationDataCollector;
use Rector\Doctrine\PhpDocParser\Ast\PhpDoc\PhpDocTagNodeFactory;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -45,14 +46,21 @@ final class AddUuidMirrorForRelationPropertyRector extends AbstractRector
*/
private $phpDocTagRemover;
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(
PhpDocTagNodeFactory $phpDocTagNodeFactory,
UuidMigrationDataCollector $uuidMigrationDataCollector,
PhpDocTagRemover $phpDocTagRemover
PhpDocTagRemover $phpDocTagRemover,
DoctrineDocBlockResolver $doctrineDocBlockResolver
) {
$this->phpDocTagNodeFactory = $phpDocTagNodeFactory;
$this->uuidMigrationDataCollector = $uuidMigrationDataCollector;
$this->phpDocTagRemover = $phpDocTagRemover;
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
@ -148,7 +156,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (! $this->isDoctrineEntityClass($node)) {
if (! $this->doctrineDocBlockResolver->isDoctrineEntityClass($node)) {
return null;
}
@ -176,7 +184,7 @@ CODE_SAMPLE
return true;
}
$targetEntity = $this->getTargetEntity($property);
$targetEntity = $this->doctrineDocBlockResolver->getTargetEntity($property);
if ($targetEntity === null) {
return true;
}

View File

@ -15,6 +15,7 @@ use Rector\Core\PhpParser\Node\Manipulator\ClassDependencyManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Doctrine\NodeFactory\EntityUuidNodeFactory;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -35,12 +36,19 @@ final class AlwaysInitializeUuidInEntityRector extends AbstractRector
*/
private $classDependencyManipulator;
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(
ClassDependencyManipulator $classDependencyManipulator,
EntityUuidNodeFactory $entityUuidNodeFactory
EntityUuidNodeFactory $entityUuidNodeFactory,
DoctrineDocBlockResolver $doctrineDocBlockResolver
) {
$this->entityUuidNodeFactory = $entityUuidNodeFactory;
$this->classDependencyManipulator = $classDependencyManipulator;
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
@ -102,7 +110,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (! $this->isDoctrineEntityClass($node)) {
if (! $this->doctrineDocBlockResolver->isDoctrineEntityClass($node)) {
return null;
}

View File

@ -69,6 +69,7 @@ CODE_SAMPLE
}
$entityTagValueNode->removeRepositoryClass();
$phpDocInfo->markAsChanged();
return $node;
}

View File

@ -9,6 +9,7 @@ use PhpParser\Node\Stmt\Property;
use Ramsey\Uuid\UuidInterface;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\AbstractDoctrineTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\ColumnTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\Property_\GeneratedValueTagValueNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\JMS\SerializerTypeTagValueNode;
@ -91,7 +92,8 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (! $this->isDoctrineProperty($node)) {
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
if (! $phpDocInfo->hasByType(AbstractDoctrineTagValueNode::class)) {
return null;
}

View File

@ -15,7 +15,6 @@ use PhpParser\Node\Stmt\Interface_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\ChangesReporting\Collector\RectorChangeCollector;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use ReflectionMethod;
@ -29,19 +28,13 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class DowngradeParameterTypeWideningRector extends AbstractRector
{
/**
* @var RectorChangeCollector
*/
private $rectorChangeCollector;
/**
* @var PhpDocTypeChanger
*/
private $phpDocTypeChanger;
public function __construct(RectorChangeCollector $rectorChangeCollector, PhpDocTypeChanger $phpDocTypeChanger)
public function __construct(PhpDocTypeChanger $phpDocTypeChanger)
{
$this->rectorChangeCollector = $rectorChangeCollector;
$this->phpDocTypeChanger = $phpDocTypeChanger;
}
@ -256,8 +249,6 @@ CODE_SAMPLE
// Remove the type
$param->type = null;
$this->rectorChangeCollector->notifyNodeFileInfo($param);
}
private function removeParamTypeFromMethodForChildren(

View File

@ -24,5 +24,6 @@ final class VarTagValueNodeRenamer
}
$varTagValueNode->variableName = '$' . $expectedName;
$phpDocInfo->markAsChanged();
}
}

View File

@ -12,6 +12,8 @@ use PhpParser\Node\Stmt\Unset_;
use PHPStan\Type\ObjectType;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NetteCodeQuality\NodeResolver\FormVariableInputNameTypeResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\PackageBuilder\Php\TypeChecker;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -27,9 +29,17 @@ final class ChangeFormArrayAccessToAnnotatedControlVariableRector extends Abstra
*/
private $formVariableInputNameTypeResolver;
public function __construct(FormVariableInputNameTypeResolver $formVariableInputNameTypeResolver)
{
/**
* @var TypeChecker
*/
private $typeChecker;
public function __construct(
FormVariableInputNameTypeResolver $formVariableInputNameTypeResolver,
TypeChecker $typeChecker
) {
$this->formVariableInputNameTypeResolver = $formVariableInputNameTypeResolver;
$this->typeChecker = $typeChecker;
}
public function getRuleDefinition(): RuleDefinition
@ -91,7 +101,8 @@ CODE_SAMPLE
return null;
}
if ($this->hasParentTypes($node, [Isset_::class, Unset_::class])) {
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($this->typeChecker->isInstanceOf($parent, [Isset_::class, Unset_::class])) {
return null;
}

View File

@ -147,6 +147,8 @@ CODE_SAMPLE
private function decorateParamWithPropertyPhpDocInfo(Property $property, Param $param): void
{
$propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$propertyPhpDocInfo->markAsChanged();
$param->setAttribute(AttributeKey::PHP_DOC_INFO, $propertyPhpDocInfo);
// make sure the docblock is useful

View File

@ -11,7 +11,6 @@ use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Rector\AbstractPHPUnitRector;
use Rector\Core\Reflection\ClassMethodReflectionFactory;
use Rector\FileSystemRector\Parser\FileInfoParser;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use ReflectionMethod;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -69,10 +68,8 @@ final class AddDoesNotPerformAssertionToNonAssertingTestRector extends AbstractP
public function __construct(
ClassMethodReflectionFactory $classMethodReflectionFactory,
DocBlockManipulator $docBlockManipulator,
FileInfoParser $fileInfoParser
) {
$this->docBlockManipulator = $docBlockManipulator;
$this->fileInfoParser = $fileInfoParser;
$this->classMethodReflectionFactory = $classMethodReflectionFactory;
}

View File

@ -94,8 +94,6 @@ CODE_SAMPLE
$seeTagNode = $this->createSeePhpDocTagNode($testCaseClassName);
$phpDocInfo->addPhpDocTagNode($seeTagNode);
$this->notifyNodeFileInfo($node);
return $node;
}

View File

@ -120,6 +120,8 @@ CODE_SAMPLE
$newMethodName = trim($newMethodName, '()');
$this->providerMethodNamesToNewNames[$oldMethodName] = $newMethodName;
$phpDocInfo->markAsChanged();
}
}
}

View File

@ -45,6 +45,8 @@ final class ClassConstantFactory
$classConst->flags = $property->flags & ~ Class_::MODIFIER_STATIC;
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$phpDocInfo->markAsChanged();
$classConst->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
return $classConst;

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Caching\Contract\Rector\ZeroCacheRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpAttribute\ValueObject\TagName;
use Rector\Privatization\NodeAnalyzer\ClassMethodExternalCallNodeAnalyzer;
@ -44,12 +45,19 @@ final class PrivatizeLocalOnlyMethodRector extends AbstractRector implements Zer
*/
private $classMethodExternalCallNodeAnalyzer;
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(
ClassMethodExternalCallNodeAnalyzer $classMethodExternalCallNodeAnalyzer,
ClassMethodVisibilityVendorLockResolver $classMethodVisibilityVendorLockResolver
ClassMethodVisibilityVendorLockResolver $classMethodVisibilityVendorLockResolver,
DoctrineDocBlockResolver $doctrineDocBlockResolver
) {
$this->classMethodVisibilityVendorLockResolver = $classMethodVisibilityVendorLockResolver;
$this->classMethodExternalCallNodeAnalyzer = $classMethodExternalCallNodeAnalyzer;
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
@ -209,7 +217,7 @@ CODE_SAMPLE
return true;
}
if ($this->isDoctrineEntityClass($class)) {
if ($this->doctrineDocBlockResolver->isDoctrineEntityClass($class)) {
return true;
}

View File

@ -7,6 +7,7 @@ namespace Rector\Privatization\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -15,6 +16,16 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class FinalizeClassesWithoutChildrenRector extends AbstractRector
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Finalize every class that has no children', [
@ -66,13 +77,16 @@ CODE_SAMPLE
if ($node->isFinal()) {
return null;
}
if ($node->isAbstract()) {
return null;
}
if ($this->isAnonymousClass($node)) {
return null;
}
if ($this->isDoctrineEntityClass($node)) {
if ($this->doctrineDocBlockResolver->isDoctrineEntityClass($node)) {
return null;
}

View File

@ -23,7 +23,7 @@ use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\ClassExistenceStaticHelper;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockClassRenamer;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
@ -34,11 +34,6 @@ final class ClassRenamer
*/
private $alreadyProcessedClasses = [];
/**
* @var DocBlockManipulator
*/
private $docBlockManipulator;
/**
* @var NodeNameResolver
*/
@ -69,22 +64,27 @@ final class ClassRenamer
*/
private $phpDocInfoFactory;
/**
* @var DocBlockClassRenamer
*/
private $docBlockClassRenamer;
public function __construct(
BetterNodeFinder $betterNodeFinder,
SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
ClassNaming $classNaming,
DocBlockManipulator $docBlockManipulator,
NodeNameResolver $nodeNameResolver,
PhpDocClassRenamer $phpDocClassRenamer,
PhpDocInfoFactory $phpDocInfoFactory
PhpDocInfoFactory $phpDocInfoFactory,
DocBlockClassRenamer $docBlockClassRenamer
) {
$this->docBlockManipulator = $docBlockManipulator;
$this->nodeNameResolver = $nodeNameResolver;
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->phpDocClassRenamer = $phpDocClassRenamer;
$this->classNaming = $classNaming;
$this->betterNodeFinder = $betterNodeFinder;
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->docBlockClassRenamer = $docBlockClassRenamer;
}
/**
@ -126,7 +126,7 @@ final class ClassRenamer
$oldClassType = new ObjectType($oldClass);
$newClassType = new FullyQualifiedObjectType($newClass);
$this->docBlockManipulator->changeType($phpDocInfo, $node, $oldClassType, $newClassType);
$this->docBlockClassRenamer->renamePhpDocType($phpDocInfo, $oldClassType, $newClassType, $node);
}
$this->phpDocClassRenamer->changeTypeInAnnotationTypes($phpDocInfo, $oldToNewClasses);

View File

@ -7,6 +7,7 @@ namespace Rector\Restoration\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\Rector\AbstractRector;
use Rector\Doctrine\PhpDocParser\DoctrineDocBlockResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -15,6 +16,16 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class RemoveFinalFromEntityRector extends AbstractRector
{
/**
* @var DoctrineDocBlockResolver
*/
private $doctrineDocBlockResolver;
public function __construct(DoctrineDocBlockResolver $doctrineDocBlockResolver)
{
$this->doctrineDocBlockResolver = $doctrineDocBlockResolver;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Remove final from Doctrine entities', [
@ -57,7 +68,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (! $this->isDoctrineEntityClass($node)) {
if (! $this->doctrineDocBlockResolver->isDoctrineEntityClass($node)) {
return null;
}

View File

@ -153,6 +153,7 @@ CODE_SAMPLE
if (! $attributeAwareReturnTagValueNode instanceof AttributeAwareReturnTagValueNode) {
return;
}
if (! $phpDocInfo->getReturnType() instanceof MixedType) {
return;
}
@ -166,6 +167,7 @@ CODE_SAMPLE
}
$attributeAwareReturnTagValueNode->type = $fullyQualifiedTypeNode;
$phpDocInfo->markAsChanged();
}
}
}

View File

@ -75,6 +75,7 @@ CODE_SAMPLE
}
$sensioRouteTagValueNode->removeService();
$phpDocInfo->markAsChanged();
return $node;
}

View File

@ -20,7 +20,6 @@ use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Doctrine\AbstractDoctrineTa
use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\JMS\SerializerTypeTagValueNode;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
use Rector\Doctrine\AbstractRector\DoctrineTrait;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\ReadWrite\Guard\VariableToConstantGuard;
use Rector\ReadWrite\NodeAnalyzer\ReadWritePropertyAnalyzer;
@ -31,8 +30,6 @@ use Symplify\PackageBuilder\Php\TypeChecker;
*/
final class PropertyManipulator
{
use DoctrineTrait;
/**
* @var BetterNodeFinder
*/

View File

@ -23,11 +23,11 @@ use PhpParser\Node\Stmt\TraitUse;
use PhpParser\Node\Stmt\Use_;
use PhpParser\PrettyPrinter\Standard;
use Rector\Comments\CommentRemover;
use Rector\Comments\NodeDocBlock\DocBlockUpdater;
use Rector\Core\PhpParser\Node\CustomNode\FileNode;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\Core\PhpParser\Printer\Whitespace\IndentCharacterDetector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
/**
* @see \Rector\Core\Tests\PhpParser\Printer\BetterStandardPrinterTest
@ -72,9 +72,9 @@ final class BetterStandardPrinter extends Standard
private $tabOrSpaceIndentCharacter = ' ';
/**
* @var DocBlockManipulator
* @var DocBlockUpdater
*/
private $docBlockManipulator;
private $docBlockUpdater;
/**
* @var CommentRemover
@ -98,7 +98,7 @@ final class BetterStandardPrinter extends Standard
CommentRemover $commentRemover,
AnnotationFormatRestorer $annotationFormatRestorer,
IndentCharacterDetector $indentCharacterDetector,
DocBlockManipulator $docBlockManipulator,
DocBlockUpdater $docBlockUpdater,
array $options = []
) {
parent::__construct($options);
@ -112,7 +112,7 @@ final class BetterStandardPrinter extends Standard
$this->commentRemover = $commentRemover;
$this->annotationFormatRestorer = $annotationFormatRestorer;
$this->indentCharacterDetector = $indentCharacterDetector;
$this->docBlockManipulator = $docBlockManipulator;
$this->docBlockUpdater = $docBlockUpdater;
}
/**
@ -531,7 +531,7 @@ final class BetterStandardPrinter extends Standard
continue;
}
$this->docBlockManipulator->updateNodeWithPhpDocInfo($node);
$this->docBlockUpdater->updateNodeWithPhpDocInfo($node);
}
}

View File

@ -21,7 +21,6 @@ use PhpParser\NodeVisitorAbstract;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Configuration\Option;
use Rector\Core\Contract\Rector\PhpRectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Exclusion\ExclusionManager;
use Rector\Core\Logging\CurrentRectorProvider;
use Rector\Core\NodeAnalyzer\ClassNodeAnalyzer;
@ -29,7 +28,6 @@ use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\Rector\AbstractRector\AbstractRectorTrait;
use Rector\Core\ValueObject\ProjectType;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
@ -57,11 +55,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
AttributeKey::RESOLVED_NAME,
];
/**
* @var string
*/
private const COMMENTS = 'comments';
/**
* @var BuilderFactory
*/
@ -77,21 +70,11 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
*/
protected $phpVersionProvider;
/**
* @var DocBlockManipulator
*/
protected $docBlockManipulator;
/**
* @var StaticTypeMapper
*/
protected $staticTypeMapper;
/**
* @var SmartFileInfo
*/
private $currentFileInfo;
/**
* @var SymfonyStyle
*/
@ -135,7 +118,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
PhpVersionProvider $phpVersionProvider,
BuilderFactory $builderFactory,
ExclusionManager $exclusionManager,
DocBlockManipulator $docBlockManipulator,
StaticTypeMapper $staticTypeMapper,
ParameterProvider $parameterProvider,
CurrentRectorProvider $currentRectorProvider,
@ -147,7 +129,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
$this->phpVersionProvider = $phpVersionProvider;
$this->builderFactory = $builderFactory;
$this->exclusionManager = $exclusionManager;
$this->docBlockManipulator = $docBlockManipulator;
$this->staticTypeMapper = $staticTypeMapper;
$this->parameterProvider = $parameterProvider;
$this->currentRectorProvider = $currentRectorProvider;
@ -166,34 +147,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
return parent::beforeTraverse($nodes);
}
/**
* @param string[] $types
*/
public function hasParentTypes(Node $node, array $types): bool
{
foreach ($types as $type) {
if (! is_a($type, Node::class, true)) {
throw new ShouldNotHappenException(__METHOD__);
}
if ($this->hasParentType($node, $type)) {
return true;
}
}
return false;
}
public function hasParentType(Node $node, string $type): bool
{
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if (! $parent instanceof Node) {
return false;
}
return is_a($parent, $type, true);
}
/**
* @return Expression|Node|null
*/
@ -204,24 +157,12 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
return null;
}
$this->currentFileInfo = $node->getAttribute(SmartFileInfo::class);
$this->currentRectorProvider->changeCurrentRector($this);
// mostly for PHP doc and change notifications
// for PHP doc info factory and change notifier
$this->currentNodeProvider->setNode($node);
// already removed
if ($this->isNodeRemoved($node)) {
return null;
}
if ($this->exclusionManager->isNodeSkippedByRector($node, $this)) {
return null;
}
$fileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
if ($fileInfo instanceof SmartFileInfo && $this->skipper->shouldSkipElementAndFileInfo($this, $fileInfo)) {
if ($this->shouldSkipCurrentNode($node)) {
return null;
}
@ -293,7 +234,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
protected function mirrorComments(Node $newNode, Node $oldNode): void
{
$newNode->setAttribute(AttributeKey::PHP_DOC_INFO, $oldNode->getAttribute(AttributeKey::PHP_DOC_INFO));
$newNode->setAttribute(self::COMMENTS, $oldNode->getAttribute(self::COMMENTS));
$newNode->setAttribute(AttributeKey::COMMENTS, $oldNode->getAttribute(AttributeKey::COMMENTS));
}
protected function rollbackComments(Node $node, Comment $comment): void
@ -315,7 +256,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
$ifStmt->setAttribute(AttributeKey::PHP_DOC_INFO, $currentPhpDocInfo);
// move // comments
$ifStmt->setAttribute(self::COMMENTS, $node->getComments());
$ifStmt->setAttribute(AttributeKey::COMMENTS, $node->getComments());
}
$this->addNodeAfterNode($ifStmt, $node);
@ -373,15 +314,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
return $newArgs;
}
protected function getFileInfo(): SmartFileInfo
{
if ($this->currentFileInfo === null) {
throw new ShouldNotHappenException();
}
return $this->currentFileInfo;
}
protected function unwrapExpression(Stmt $stmt): Node
{
if ($stmt instanceof Expression) {
@ -472,4 +404,22 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
// names are the same
return $this->areNodesEqual($originalNode->getAttribute(AttributeKey::ORIGINAL_NAME), $node);
}
private function shouldSkipCurrentNode(Node $node): bool
{
if ($this->isNodeRemoved($node)) {
return true;
}
if ($this->exclusionManager->isNodeSkippedByRector($node, $this)) {
return true;
}
$fileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
if (! $fileInfo instanceof SmartFileInfo) {
return false;
}
return $this->skipper->shouldSkipElementAndFileInfo($this, $fileInfo);
}
}

View File

@ -8,7 +8,6 @@ use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\ChangesReporting\Rector\AbstractRector\NotifyingRemovingNodeTrait;
use Rector\Doctrine\AbstractRector\DoctrineTrait;
use Rector\FileSystemRector\Behavior\FileSystemRectorTrait;
use Rector\PostRector\Rector\AbstractRector\NodeCommandersTrait;
@ -17,7 +16,6 @@ trait AbstractRectorTrait
use FileSystemRectorTrait;
use PhpDocTrait;
use RemovedAndAddedFilesTrait;
use DoctrineTrait;
use NodeTypeResolverTrait;
use NameResolverTrait;
use ConstFetchAnalyzerTrait;

View File

@ -57,7 +57,7 @@ final class LogIdentifierAndResolverValueInConstantClassMethodRector extends Abs
$node->stmts = array_merge([$firstStmt], [$assignExpression], (array) $node->stmts);
// 2. record value in each return
$this->traverseNodesWithCallable((array) $node->stmts, function (Node $node): ?Return_ {
$this->traverseNodesWithCallable($node->stmts, function (Node $node): ?Return_ {
if (! $node instanceof Return_) {
return null;
}

View File

@ -42,7 +42,6 @@ final class SymfonyConfigRectorValueObjectResolver
$parent = $parent->getAttribute(PHPStanAttributeKey::PARENT);
}
/** @var StaticCall|null $inlineStaticCall */
$inlineStaticCall = $this->nodeFinder->findFirst($parent, function (Node $node): bool {
if (! $node instanceof StaticCall) {
return false;
@ -51,13 +50,12 @@ final class SymfonyConfigRectorValueObjectResolver
return $this->simpleNameResolver->isName($node->class, self::INLINE_CLASS_NAME);
});
if ($inlineStaticCall === null) {
if (! $inlineStaticCall instanceof StaticCall) {
return null;
}
/** @var New_|null $new */
$new = $this->nodeFinder->findFirstInstanceOf($inlineStaticCall, New_::class);
if ($new === null) {
if (! $new instanceof New_) {
return null;
}

View File

@ -11,7 +11,7 @@ final class SupportedTypeMappersDataProvider
/**
* @var TypeMapperInterface[]
*/
private $typeMappers;
private $typeMappers = [];
/**
* @param TypeMapperInterface[] $typeMappers

View File

@ -14,7 +14,7 @@ final class MissingPHPStanTypeMappersResolver
/**
* @var SupportedTypeMappersDataProvider
*/
private $supportedTypeMappersResolver;
private $supportedTypeMappersDataProvider;
/**
* @var PHPStanTypeClassFinder
@ -23,9 +23,9 @@ final class MissingPHPStanTypeMappersResolver
public function __construct(
PHPStanTypeClassFinder $phpStanTypeClassFinder,
SupportedTypeMappersDataProvider $supportedTypeMappersResolver
SupportedTypeMappersDataProvider $supportedTypeMappersDataProvider
) {
$this->supportedTypeMappersResolver = $supportedTypeMappersResolver;
$this->supportedTypeMappersDataProvider = $supportedTypeMappersDataProvider;
$this->phpStanTypeClassFinder = $phpStanTypeClassFinder;
}
@ -35,7 +35,7 @@ final class MissingPHPStanTypeMappersResolver
public function resolve(): array
{
$typeClasses = $this->phpStanTypeClassFinder->find();
$supportedTypeClasses = $this->supportedTypeMappersResolver->provide();
$supportedTypeClasses = $this->supportedTypeMappersDataProvider->provide();
$unsupportedTypeClasses = [];
foreach ($typeClasses as $phpStanTypeClass) {

View File

@ -15,7 +15,6 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Console\ShellCode;
use Symplify\SmartFileSystem\Finder\FinderSanitizer;
use Symplify\SmartFileSystem\SmartFileInfo;
use Symplify\SmartFileSystem\SmartFileSystem;
@ -74,11 +73,6 @@ final class ValidateFixtureClassnameCommand extends Command
'property',
];
/**
* @var FinderSanitizer
*/
private $finderSanitizer;
/**
* @var SymfonyStyle
*/
@ -102,7 +96,7 @@ final class ValidateFixtureClassnameCommand extends Command
/**
* @var NamespaceMatcher
*/
private $namespaceMather;
private $namespaceMatcher;
/**
* @var ExpectedNameResolver
@ -110,22 +104,19 @@ final class ValidateFixtureClassnameCommand extends Command
private $expectedNameResolver;
public function __construct(
FinderSanitizer $finderSanitizer,
SymfonyStyle $symfonyStyle,
ExpectedNameResolver $expectedNameResolver,
SmartFileSystem $smartFileSystem,
FixtureFinder $fixtureFinder,
NamespaceMatcher $namespaceMather
NamespaceMatcher $namespaceMatcher
) {
$this->finderSanitizer = $finderSanitizer;
parent::__construct();
$this->symfonyStyle = $symfonyStyle;
$this->currentDirectory = getcwd();
$this->smartFileSystem = $smartFileSystem;
parent::__construct();
$this->fixtureFinder = $fixtureFinder;
$this->namespaceMather = $namespaceMather;
$this->namespaceMatcher = $namespaceMatcher;
$this->expectedNameResolver = $expectedNameResolver;
}
@ -149,7 +140,7 @@ final class ValidateFixtureClassnameCommand extends Command
continue;
}
$path = ltrim(substr($paths[0], strlen($this->currentDirectory)) . '/tests', '/');
$path = ltrim(Strings::substring($paths[0], strlen($this->currentDirectory)) . '/tests', '/');
$expectedNamespace = $this->expectedNameResolver->resolve($path, $paths[1]);
if ($expectedNamespace === null) {
@ -160,8 +151,12 @@ final class ValidateFixtureClassnameCommand extends Command
$fileContent = $this->smartFileSystem->readFile((string) $fixtureFileInfo);
$matchAll = Strings::matchAll($fileContent, self::NAMESPACE_REGEX);
$namespaceMatcherIsFoundCorrectNamespace = $this->namespaceMatcher->isFoundCorrectNamespace(
$matchAll,
$expectedNamespace
);
if (! $this->namespaceMather->isFoundCorrectNamespace($matchAll, $expectedNamespace)) {
if (! $namespaceMatcherIsFoundCorrectNamespace) {
continue;
}
@ -206,12 +201,14 @@ final class ValidateFixtureClassnameCommand extends Command
bool $optionFix
): array {
$matchAll = Strings::matchAll($fileContent, self::CLASS_REGEX);
if ($matchAll === [] || count($matchAll) > 2) {
if ($matchAll === []) {
return $incorrectClassNameFiles;
}
if (count($matchAll) > 2) {
return $incorrectClassNameFiles;
}
$fileName = substr($fixtureFile->getFileName(), 0, -8);
$fileName = Strings::substring($fixtureFile->getFileName(), 0, -8);
if (in_array($fileName, self::EXCLUDE_NAMES, true)) {
return $incorrectClassNameFiles;
@ -250,7 +247,7 @@ final class ValidateFixtureClassnameCommand extends Command
string $expectedClassName
): void {
$newContent = str_replace('class ' . $incorrectClassName, 'class ' . $expectedClassName, $incorrectFileContent);
$this->smartFileSystem->dumpFile((string) $incorrectClassNameFile, $newContent);
$this->smartFileSystem->dumpFile($incorrectClassNameFile, $newContent);
}
/**

View File

@ -14,7 +14,6 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Console\ShellCode;
use Symplify\SmartFileSystem\Finder\FinderSanitizer;
use Symplify\SmartFileSystem\SmartFileSystem;
final class ValidateFixtureNamespaceCommand extends Command
@ -25,11 +24,6 @@ final class ValidateFixtureNamespaceCommand extends Command
*/
private const NAMESPACE_REGEX = '#^namespace (.*);$#msU';
/**
* @var FinderSanitizer
*/
private $finderSanitizer;
/**
* @var SymfonyStyle
*/
@ -61,21 +55,18 @@ final class ValidateFixtureNamespaceCommand extends Command
private $expectedNameResolver;
public function __construct(
FinderSanitizer $finderSanitizer,
SymfonyStyle $symfonyStyle,
SmartFileSystem $smartFileSystem,
FixtureFinder $fixtureFinder,
NamespaceMatcher $namespaceMatcher,
ExpectedNameResolver $expectedNameResolver
) {
$this->finderSanitizer = $finderSanitizer;
parent::__construct();
$this->symfonyStyle = $symfonyStyle;
$this->currentDirectory = getcwd();
$this->smartFileSystem = $smartFileSystem;
$this->fixtureFinder = $fixtureFinder;
parent::__construct();
$this->namespaceMatcher = $namespaceMatcher;
$this->expectedNameResolver = $expectedNameResolver;
}
@ -100,7 +91,7 @@ final class ValidateFixtureNamespaceCommand extends Command
continue;
}
$path = ltrim(substr($paths[0], strlen($this->currentDirectory)) . '/tests', '/');
$path = ltrim(Strings::substring($paths[0], strlen($this->currentDirectory)) . '/tests', '/');
$expectedNamespace = $this->expectedNameResolver->resolve($path, $paths[1]);
if ($expectedNamespace === null) {
@ -157,7 +148,7 @@ final class ValidateFixtureNamespaceCommand extends Command
'namespace ' . $expectedNamespace,
$incorrectFileContent
);
$this->smartFileSystem->dumpFile((string) $incorrectNamespaceFile, $newContent);
$this->smartFileSystem->dumpFile($incorrectNamespaceFile, $newContent);
}
/**

View File

@ -19,7 +19,12 @@ final class NamespaceMatcher
if ($countMatchAll === 1 && $matchAll[0][1] === $expectedNamespace) {
return true;
}
return $countMatchAll === 2 && $matchAll[0][1] === $expectedNamespace && $matchAll[1][1] === $expectedNamespace;
if ($countMatchAll !== 2) {
return false;
}
if ($matchAll[0][1] !== $expectedNamespace) {
return false;
}
return $matchAll[1][1] === $expectedNamespace;
}
}

View File

@ -10,6 +10,7 @@ final class TooLongFilesResolver
{
/**
* In windows the max-path length is 260 chars. we give a bit room for the path up to the rector project
* @var int
*/
public const MAX_FILE_LENGTH = 200;
@ -19,7 +20,7 @@ final class TooLongFilesResolver
*/
public function resolve(array $fileInfos): array
{
return array_filter($fileInfos, function (SmartFileInfo $fileInfo) {
return array_filter($fileInfos, function (SmartFileInfo $fileInfo): bool {
$filePathLength = strlen($fileInfo->getRealPath());
return $filePathLength > self::MAX_FILE_LENGTH;
});