From 5600cf8d4d98a9f224e7d774e93c25ac86b1f855 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Tue, 31 Mar 2020 20:46:33 +0200 Subject: [PATCH] move node adding to PostRector --- config/set/coding-style/coding-style.yaml | 1 - docs/AllRectorsOverview.md | 41 +---- .../src/Application/PostFileProcessor.php | 104 ++--------- .../src/Collector/NodesToAddCollector.php | 105 +++++++++++ .../src/Collector/UseNodesToAddCollector.php | 44 +---- .../Contract/Rector/PostRectorInterface.php | 6 - .../src/Rector/AbstractPostRector.php | 9 - .../AbstractRector/NodeCommandersTrait.php | 16 +- ...Rector.php => NameImportingPostRector.php} | 4 +- .../src/Rector/NodeAddingPostRector.php | 64 +++++++ .../src/Rector/NodeRemovingRector.php | 2 +- .../src/Rector/NodeToReplacePostRector.php | 8 +- .../src/Rector/PropertyAddingPostRector.php | 2 +- .../src/Rector/UseAddingPostRector.php | 66 ++----- .../Validator/CanImportBeAddedValidator.php | 48 +++++ phpstan.neon | 7 +- .../src/Imports/ImportSkipper.php | 20 +- .../ImportFullyQualifiedNamesRector.php | 126 ------------- .../ImportFullyQualifiedNamesRectorTest.php | 11 +- ...ImportRootNamespaceClassesDisabledTest.php | 11 +- .../NonNamespacedTest.php | 10 +- .../src/AssertManipulator.php | 26 +-- .../AutoImportNamesParameterTest.php | 10 +- .../FunctionAutoImportNamesParameterTest.php | 10 +- src/Application/FileProcessor.php | 3 +- .../PhpParser/Node/CommanderInterface.php | 23 --- .../Node/Commander/NodeAddingCommander.php | 174 ------------------ src/Rector/AbstractRector.php | 4 - .../PHPUnit/AbstractGenericRectorTestCase.php | 2 +- .../PHPUnit/AbstractRectorTestCase.php | 23 --- 30 files changed, 347 insertions(+), 633 deletions(-) create mode 100644 packages/post-rector/src/Collector/NodesToAddCollector.php rename packages/post-rector/src/Rector/{NameImportingRector.php => NameImportingPostRector.php} (94%) create mode 100644 packages/post-rector/src/Rector/NodeAddingPostRector.php create mode 100644 packages/post-rector/src/Validator/CanImportBeAddedValidator.php delete mode 100644 rules/coding-style/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php delete mode 100644 src/Contract/PhpParser/Node/CommanderInterface.php delete mode 100644 src/PhpParser/Node/Commander/NodeAddingCommander.php diff --git a/config/set/coding-style/coding-style.yaml b/config/set/coding-style/coding-style.yaml index 1be1ff469987..1987e9ad60d3 100644 --- a/config/set/coding-style/coding-style.yaml +++ b/config/set/coding-style/coding-style.yaml @@ -12,7 +12,6 @@ services: Rector\CodingStyle\Rector\String_\SymplifyQuoteEscapeRector: null Rector\CodingStyle\Rector\ClassConst\SplitGroupedConstantsAndPropertiesRector: null Rector\CodingStyle\Rector\String_\SplitStringClassConstantToClassConstFetchRector: null - Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: null # 'ClassName' → ClassName::class Rector\Php55\Rector\String_\StringClassNameToClassConstantRector: null diff --git a/docs/AllRectorsOverview.md b/docs/AllRectorsOverview.md index 5f9bde6e36fd..ef98f055393e 100644 --- a/docs/AllRectorsOverview.md +++ b/docs/AllRectorsOverview.md @@ -2075,35 +2075,6 @@ Changes === false to negate !
-### `ImportFullyQualifiedNamesRector` - -- class: [`Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector`](/../master/rules/coding-style/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php) -- [test fixtures](/../master/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Fixture) - -Import fully qualified names to use statements - -```diff -+use SomeAnother\AnotherClass; -+use DateTime; -+ - class SomeClass - { - public function create() - { -- return SomeAnother\AnotherClass; -+ return AnotherClass; - } - - public function createDate() - { -- return new \DateTime(); -+ return new DateTime(); - } - } -``` - -
- ### `MakeInheritedMethodVisibilitySameAsParentRector` - class: [`Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector`](/../master/rules/coding-style/src/Rector/ClassMethod/MakeInheritedMethodVisibilitySameAsParentRector.php) @@ -7854,14 +7825,22 @@ Remove php version checks if they are passed ## PostRector -### `NameImportingRector` +### `NameImportingPostRector` -- class: [`Rector\PostRector\Rector\NameImportingRector`](/../master/packages/post-rector/src/Rector/NameImportingRector.php) +- class: [`Rector\PostRector\Rector\NameImportingPostRector`](/../master/packages/post-rector/src/Rector/NameImportingPostRector.php) Imports names
+### `NodeAddingPostRector` + +- class: [`Rector\PostRector\Rector\NodeAddingPostRector`](/../master/packages/post-rector/src/Rector/NodeAddingPostRector.php) + +Post Rector that adds nodes + +
+ ### `NodeRemovingRector` - class: [`Rector\PostRector\Rector\NodeRemovingRector`](/../master/packages/post-rector/src/Rector/NodeRemovingRector.php) diff --git a/packages/post-rector/src/Application/PostFileProcessor.php b/packages/post-rector/src/Application/PostFileProcessor.php index 443412f3bca0..6b4db9c1d12c 100644 --- a/packages/post-rector/src/Application/PostFileProcessor.php +++ b/packages/post-rector/src/Application/PostFileProcessor.php @@ -6,120 +6,56 @@ use PhpParser\Node; use PhpParser\NodeTraverser; -use Rector\Core\Contract\PhpParser\Node\CommanderInterface; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\NodeTypeResolver\FileSystem\CurrentFileInfoProvider; -use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PostRector\Contract\Rector\PostRectorInterface; -use Rector\PostRector\Rector\UseAddingPostRector; -use Symplify\SmartFileSystem\SmartFileInfo; -final class PostFileProcessor extends NodeTraverser +final class PostFileProcessor { /** - * @var CommanderInterface[]|PostRectorInterface[] + * @var PostRectorInterface[] */ - private $commanders = []; + private $postRectors = []; /** - * @var CurrentFileInfoProvider - */ - private $currentFileInfoProvider; - - /** - * @var UseAddingPostRector - */ - private $useAddingPostRector; - - /** - * @param CommanderInterface[] $commanders * @param PostRectorInterface[] $postRectors */ - public function __construct( - CurrentFileInfoProvider $currentFileInfoProvider, - array $commanders, - array $postRectors, - UseAddingPostRector $useAddingPostRector - ) { - // A. slowly remove... - $commanders = array_merge($commanders, $postRectors); - - $this->sortByPriorityAndSetCommanders($commanders); - $this->currentFileInfoProvider = $currentFileInfoProvider; - - // B. refactor into ↓ - foreach ($commanders as $commander) { - if ($commander instanceof PostRectorInterface) { - $this->addVisitor($commander); - } - } - - $this->useAddingPostRector = $useAddingPostRector; + public function __construct(array $postRectors) + { + $this->sortByPriorityAndSetCommanders($postRectors); } /** * @param Node[] $nodes * @return Node[] */ - public function traverseNodes(array $nodes): array + public function traverse(array $nodes): array { - $this->setCurrentFileInfo($nodes); - - // A. commanders - foreach ($this->commanders as $commander) { - if (! $commander instanceof CommanderInterface) { - continue; - } - - if (! $commander->isActive()) { - continue; - } - - $nodes = $commander->traverseNodes($nodes); + foreach ($this->postRectors as $postRector) { + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor($postRector); + $nodes = $nodeTraverser->traverse($nodes); } - // B. post rectors - $nodes = parent::traverse($nodes); - - // must run standalone, after NameImporitngPostRector, so it won't skip TraverseNodes() - - return $this->useAddingPostRector->traverse($nodes); + return $nodes; } /** - * @param CommanderInterface[]|PostRectorInterface[] $commanders + * @param PostRectorInterface[] $postRectors */ - private function sortByPriorityAndSetCommanders(array $commanders): void + private function sortByPriorityAndSetCommanders(array $postRectors): void { - $commandersByPriority = []; + $postRectorsByPriority = []; - foreach ($commanders as $commander) { - if (isset($commandersByPriority[$commander->getPriority()])) { + foreach ($postRectors as $postRector) { + if (isset($postRectorsByPriority[$postRector->getPriority()])) { throw new ShouldNotHappenException(); } - $commandersByPriority[$commander->getPriority()] = $commander; + $postRectorsByPriority[$postRector->getPriority()] = $postRector; } - krsort($commandersByPriority); - - $this->commanders = $commandersByPriority; - } - - /** - * @param Node[] $nodes - */ - private function setCurrentFileInfo(array $nodes): void - { - foreach ($nodes as $node) { - /** @var SmartFileInfo|null $fileInfo */ - $fileInfo = $node->getAttribute(AttributeKey::FILE_INFO); - if (! $fileInfo instanceof SmartFileInfo) { - continue; - } + krsort($postRectorsByPriority); - $this->currentFileInfoProvider->setCurrentFileInfo($fileInfo); - break; - } + $this->postRectors = $postRectorsByPriority; } } diff --git a/packages/post-rector/src/Collector/NodesToAddCollector.php b/packages/post-rector/src/Collector/NodesToAddCollector.php new file mode 100644 index 000000000000..b1b403014559 --- /dev/null +++ b/packages/post-rector/src/Collector/NodesToAddCollector.php @@ -0,0 +1,105 @@ +betterNodeFinder = $betterNodeFinder; + } + + public function isActive(): bool + { + return count($this->nodesToAddAfter) > 0 || count($this->nodesToAddBefore) > 0; + } + + public function addNodeBeforeNode(Node $addedNode, Node $positionNode): void + { + $position = $this->resolveNearestExpressionPosition($positionNode); + $this->nodesToAddBefore[$position][] = $this->wrapToExpression($addedNode); + } + + public function addNodeAfterNode(Node $addedNode, Node $positionNode): void + { + $position = $this->resolveNearestExpressionPosition($positionNode); + $this->nodesToAddAfter[$position][] = $this->wrapToExpression($addedNode); + } + + public function getNodesToAddAfterNode(Node $node): array + { + $position = spl_object_hash($node); + return $this->nodesToAddAfter[$position] ?? []; + } + + public function getNodesToAddBeforeNode(Node $node): array + { + $position = spl_object_hash($node); + return $this->nodesToAddBefore[$position] ?? []; + } + + public function clearNodesToAddAfter(Node $node): void + { + $objectHash = spl_object_hash($node); + unset($this->nodesToAddAfter[$objectHash]); + } + + public function clearNodesToAddBefore(Node $node): void + { + $objectHash = spl_object_hash($node); + unset($this->nodesToAddBefore[$objectHash]); + } + + private function resolveNearestExpressionPosition(Node $node): string + { + if ($node instanceof Expression) { + return spl_object_hash($node); + } + + // special case for "If_" + if ($node instanceof If_) { + return spl_object_hash($node); + } + + /** @var Expression|null $foundNode */ + $foundNode = $this->betterNodeFinder->findFirstAncestorInstanceOf($node, Expression::class); + if ($foundNode === null) { + $foundNode = $node; + } + + return spl_object_hash($foundNode); + } + + /** + * @param Expr|Stmt $node + */ + private function wrapToExpression(Node $node): Stmt + { + return $node instanceof Stmt ? $node : new Expression($node); + } +} diff --git a/packages/post-rector/src/Collector/UseNodesToAddCollector.php b/packages/post-rector/src/Collector/UseNodesToAddCollector.php index e7bd91342fa3..f243cef093f1 100644 --- a/packages/post-rector/src/Collector/UseNodesToAddCollector.php +++ b/packages/post-rector/src/Collector/UseNodesToAddCollector.php @@ -6,7 +6,6 @@ use PhpParser\Node; use PHPStan\Type\ObjectType; -use Rector\CodingStyle\Imports\UsedImportsResolver; use Rector\Core\Exception\ShouldNotHappenException; use Rector\NodeTypeResolver\FileSystem\CurrentFileInfoProvider; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -40,17 +39,9 @@ final class UseNodesToAddCollector implements NodeCollectorInterface */ private $functionUseImportTypesInFilePath = []; - /** - * @var UsedImportsResolver - */ - private $usedImportsResolver; - - public function __construct( - CurrentFileInfoProvider $currentFileInfoProvider, - UsedImportsResolver $usedImportsResolver - ) { + public function __construct(CurrentFileInfoProvider $currentFileInfoProvider) + { $this->currentFileInfoProvider = $currentFileInfoProvider; - $this->usedImportsResolver = $usedImportsResolver; } public function isActive(): bool @@ -94,10 +85,10 @@ public function removeShortUse(Node $node, string $shortUse): void $this->removedShortUsesInFilePath[$fileInfo->getRealPath()][] = $shortUse; } - public function clear(string $filePath): void + public function clear(SmartFileInfo $smartFileInfo): void { // clear applied imports, so isActive() doesn't return any false positives - unset($this->useImportTypesInFilePath[$filePath], $this->functionUseImportTypesInFilePath[$filePath]); + unset($this->useImportTypesInFilePath[$smartFileInfo->getRealPath()], $this->functionUseImportTypesInFilePath[$smartFileInfo->getRealPath()]); } /** @@ -110,21 +101,6 @@ public function getUseImportTypesByNode(Node $node): array return $this->useImportTypesInFilePath[$filePath] ?? []; } - public function analyseFileInfoUseStatements(Node $node): void - { - $filePath = $this->getRealPathFromNode($node); - - // already analysed - if (isset($this->useImportTypesInFilePath[$filePath])) { - return; - } - - $usedImportTypes = $this->usedImportsResolver->resolveForNode($node); - foreach ($usedImportTypes as $usedImportType) { - $this->useImportTypesInFilePath[$filePath][] = $usedImportType; - } - } - public function hasImport(Node $node, FullyQualifiedObjectType $fullyQualifiedObjectType): bool { $useImports = $this->getUseImportTypesByNode($node); @@ -186,25 +162,25 @@ public function isImportShortable(Node $node, FullyQualifiedObjectType $fullyQua /** * @return FullyQualifiedObjectType[]|AliasedObjectType[] */ - public function getUseImportTypes(string $filePath): array + public function getObjectImportsByFileInfo(SmartFileInfo $smartFileInfo): array { - return $this->useImportTypesInFilePath[$filePath] ?? []; + return $this->useImportTypesInFilePath[$smartFileInfo->getRealPath()] ?? []; } /** * @return FullyQualifiedObjectType[] */ - public function getFunctionUseImportTypesInFilePath(string $filePath): array + public function getFunctionImportsByFileInfo(SmartFileInfo $smartFileInfo): array { - return $this->functionUseImportTypesInFilePath[$filePath] ?? []; + return $this->functionUseImportTypesInFilePath[$smartFileInfo->getRealPath()] ?? []; } /** * @return string[] */ - public function getShortUsesInFilePath(string $filePath): array + public function getShortUsesByFileInfo(SmartFileInfo $smartFileInfo): array { - return $this->removedShortUsesInFilePath[$filePath] ?? []; + return $this->removedShortUsesInFilePath[$smartFileInfo->getRealPath()] ?? []; } private function getRealPathFromNode(Node $node): ?string diff --git a/packages/post-rector/src/Contract/Rector/PostRectorInterface.php b/packages/post-rector/src/Contract/Rector/PostRectorInterface.php index 84aa058dc6fd..b9351f7d7c87 100644 --- a/packages/post-rector/src/Contract/Rector/PostRectorInterface.php +++ b/packages/post-rector/src/Contract/Rector/PostRectorInterface.php @@ -4,7 +4,6 @@ namespace Rector\PostRector\Contract\Rector; -use PhpParser\Node; use PhpParser\NodeVisitor; use Rector\Core\Contract\Rector\RectorInterface; @@ -14,9 +13,4 @@ interface PostRectorInterface extends NodeVisitor, RectorInterface * Higher values are executed first */ public function getPriority(): int; - - /** - * Process Node of matched type - */ - public function refactor(Node $node): ?Node; } diff --git a/packages/post-rector/src/Rector/AbstractPostRector.php b/packages/post-rector/src/Rector/AbstractPostRector.php index d4ad1ae82fd3..30e28d034531 100644 --- a/packages/post-rector/src/Rector/AbstractPostRector.php +++ b/packages/post-rector/src/Rector/AbstractPostRector.php @@ -4,7 +4,6 @@ namespace Rector\PostRector\Rector; -use PhpParser\Node; use PhpParser\NodeVisitorAbstract; use Rector\Core\Rector\AbstractRector\NameResolverTrait; use Rector\PostRector\Contract\Rector\PostRectorInterface; @@ -12,12 +11,4 @@ abstract class AbstractPostRector extends NodeVisitorAbstract implements PostRectorInterface { use NameResolverTrait; - - /** - * @return int|Node|null - */ - final public function enterNode(Node $node) - { - return $this->refactor($node); - } } diff --git a/packages/post-rector/src/Rector/AbstractRector/NodeCommandersTrait.php b/packages/post-rector/src/Rector/AbstractRector/NodeCommandersTrait.php index 465812166ab7..9905a75ff681 100644 --- a/packages/post-rector/src/Rector/AbstractRector/NodeCommandersTrait.php +++ b/packages/post-rector/src/Rector/AbstractRector/NodeCommandersTrait.php @@ -12,9 +12,9 @@ use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use Rector\ChangesReporting\Collector\RectorChangeCollector; -use Rector\Core\PhpParser\Node\Commander\NodeAddingCommander; use Rector\PHPStan\Type\AliasedObjectType; use Rector\PHPStan\Type\FullyQualifiedObjectType; +use Rector\PostRector\Collector\NodesToAddCollector; use Rector\PostRector\Collector\NodesToRemoveCollector; use Rector\PostRector\Collector\NodesToReplaceCollector; use Rector\PostRector\Collector\PropertyToAddCollector; @@ -37,9 +37,9 @@ trait NodeCommandersTrait private $nodesToRemoveCollector; /** - * @var NodeAddingCommander + * @var NodesToAddCollector */ - private $nodeAddingCommander; + private $nodesToAddCollector; /** * @var PropertyToAddCollector @@ -61,17 +61,17 @@ trait NodeCommandersTrait */ public function autowireNodeCommandersTrait( NodesToRemoveCollector $nodesToRemoveCollector, - NodeAddingCommander $nodeAddingCommander, PropertyToAddCollector $propertyToAddCollector, UseNodesToAddCollector $useNodesToAddCollector, + NodesToAddCollector $nodesToAddCollector, NodesToReplaceCollector $nodesToReplaceCollector, RectorChangeCollector $rectorChangeCollector ): void { $this->nodesToRemoveCollector = $nodesToRemoveCollector; - $this->nodeAddingCommander = $nodeAddingCommander; $this->propertyToAddCollector = $propertyToAddCollector; $this->useNodesToAddCollector = $useNodesToAddCollector; $this->nodesToReplaceCollector = $nodesToReplaceCollector; + $this->nodesToAddCollector = $nodesToAddCollector; $this->rectorChangeCollector = $rectorChangeCollector; } @@ -87,15 +87,13 @@ protected function addUseType(ObjectType $objectType, Node $positionNode): void protected function addNodeAfterNode(Node $newNode, Node $positionNode): void { - $this->nodeAddingCommander->addNodeAfterNode($newNode, $positionNode); - + $this->nodesToAddCollector->addNodeAfterNode($newNode, $positionNode); $this->rectorChangeCollector->notifyNodeFileInfo($positionNode); } protected function addNodeBeforeNode(Node $newNode, Node $positionNode): void { - $this->nodeAddingCommander->addNodeBeforeNode($newNode, $positionNode); - + $this->nodesToAddCollector->addNodeBeforeNode($newNode, $positionNode); $this->rectorChangeCollector->notifyNodeFileInfo($positionNode); } diff --git a/packages/post-rector/src/Rector/NameImportingRector.php b/packages/post-rector/src/Rector/NameImportingPostRector.php similarity index 94% rename from packages/post-rector/src/Rector/NameImportingRector.php rename to packages/post-rector/src/Rector/NameImportingPostRector.php index 1c7ccd5489a9..8754b6e6b2e7 100644 --- a/packages/post-rector/src/Rector/NameImportingRector.php +++ b/packages/post-rector/src/Rector/NameImportingPostRector.php @@ -14,7 +14,7 @@ use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockNameImporter; use Symplify\PackageBuilder\Parameter\ParameterProvider; -final class NameImportingRector extends AbstractPostRector +final class NameImportingPostRector extends AbstractPostRector { /** * @var ParameterProvider @@ -48,7 +48,7 @@ public function __construct( $this->docBlockNameImporter = $docBlockNameImporter; } - public function refactor(Node $node): ?Node + public function enterNode(Node $node): ?Node { if (! $this->parameterProvider->provideParameter(Option::AUTO_IMPORT_NAMES)) { return null; diff --git a/packages/post-rector/src/Rector/NodeAddingPostRector.php b/packages/post-rector/src/Rector/NodeAddingPostRector.php new file mode 100644 index 000000000000..5456fb9c32eb --- /dev/null +++ b/packages/post-rector/src/Rector/NodeAddingPostRector.php @@ -0,0 +1,64 @@ +someCall(); + * + * To: + * - $this->someCall(); + * - $value = this->someNewCall(); // added expression + */ +final class NodeAddingPostRector extends AbstractPostRector +{ + /** + * @var NodesToAddCollector + */ + private $nodesToAddCollector; + + public function __construct(NodesToAddCollector $nodesToAddCollector) + { + $this->nodesToAddCollector = $nodesToAddCollector; + } + + public function getPriority(): int + { + return 1000; + } + + /** + * @return Node[]|Node|null + */ + public function leaveNode(Node $node) + { + $nodesToAddAfter = $this->nodesToAddCollector->getNodesToAddAfterNode($node); + + if ($nodesToAddAfter !== []) { + $this->nodesToAddCollector->clearNodesToAddAfter($node); + return array_merge([$node], $nodesToAddAfter); + } + + $nodesToAddBefore = $this->nodesToAddCollector->getNodesToAddBeforeNode($node); + if ($nodesToAddBefore !== []) { + $this->nodesToAddCollector->clearNodesToAddBefore($node); + return array_merge($nodesToAddBefore, [$node]); + } + + return $node; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Post Rector that adds nodes'); + } +} diff --git a/packages/post-rector/src/Rector/NodeRemovingRector.php b/packages/post-rector/src/Rector/NodeRemovingRector.php index aa55c43f039e..b29db2411d57 100644 --- a/packages/post-rector/src/Rector/NodeRemovingRector.php +++ b/packages/post-rector/src/Rector/NodeRemovingRector.php @@ -39,7 +39,7 @@ public function getPriority(): int return 800; } - public function refactor(Node $node): ?Node + public function enterNode(Node $node): ?Node { if (! $this->nodesToRemoveCollector->isActive()) { return null; diff --git a/packages/post-rector/src/Rector/NodeToReplacePostRector.php b/packages/post-rector/src/Rector/NodeToReplacePostRector.php index e60a5c245e43..192bc25d409f 100644 --- a/packages/post-rector/src/Rector/NodeToReplacePostRector.php +++ b/packages/post-rector/src/Rector/NodeToReplacePostRector.php @@ -25,13 +25,6 @@ public function getPriority(): int return 1100; } - public function refactor(Node $node): ?Node - { - // used in leave node - return null; - // TODO: Implement refactor() method. - } - public function leaveNode(Node $node): ?Node { foreach ($this->nodesToReplaceCollector->getNodes() as [$nodeToFind, $replacement]) { @@ -39,6 +32,7 @@ public function leaveNode(Node $node): ?Node return $replacement; } } + return null; } diff --git a/packages/post-rector/src/Rector/PropertyAddingPostRector.php b/packages/post-rector/src/Rector/PropertyAddingPostRector.php index 7cc51d17851f..ec17e282c3ca 100644 --- a/packages/post-rector/src/Rector/PropertyAddingPostRector.php +++ b/packages/post-rector/src/Rector/PropertyAddingPostRector.php @@ -46,7 +46,7 @@ public function getPriority(): int return 900; } - public function refactor(Node $node): ?Node + public function enterNode(Node $node): ?Node { if (! $node instanceof Class_ || $node->isAnonymous()) { return null; diff --git a/packages/post-rector/src/Rector/UseAddingPostRector.php b/packages/post-rector/src/Rector/UseAddingPostRector.php index f3d456d50b8b..b7e156b13b0b 100644 --- a/packages/post-rector/src/Rector/UseAddingPostRector.php +++ b/packages/post-rector/src/Rector/UseAddingPostRector.php @@ -5,13 +5,10 @@ namespace Rector\PostRector\Rector; use Nette\Utils\Strings; -use PhpParser\Node; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Namespace_; -use PhpParser\NodeVisitorAbstract; use Rector\CodingStyle\Application\UseImportsAdder; use Rector\CodingStyle\Application\UseImportsRemover; -use Rector\Core\Contract\Rector\RectorInterface; use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\Core\RectorDefinition\RectorDefinition; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -20,7 +17,7 @@ use Rector\PostRector\Collector\UseNodesToAddCollector; use Symplify\SmartFileSystem\SmartFileInfo; -final class UseAddingPostRector extends NodeVisitorAbstract implements RectorInterface +final class UseAddingPostRector extends AbstractPostRector { /** * @var UseImportsAdder @@ -65,22 +62,21 @@ public function __construct( * @param Stmt[] $nodes * @return Stmt[] */ - public function traverse(array $nodes): array + public function beforeTraverse(array $nodes): array { // no nodes → just return if (count($nodes) === 0) { return $nodes; } - $filePath = $this->getRealPathFromNode($nodes[0]); - - if ($filePath === null) { + $smartFileInfo = $this->getSmartFileInfo($nodes); + if ($smartFileInfo === null) { return $nodes; } - $useImportTypes = $this->useNodesToAddCollector->getUseImportTypes($filePath); - $functionUseImportTypes = $this->useNodesToAddCollector->getFunctionUseImportTypesInFilePath($filePath); - $removedShortUses = $this->useNodesToAddCollector->getShortUsesInFilePath($filePath); + $useImportTypes = $this->useNodesToAddCollector->getObjectImportsByFileInfo($smartFileInfo); + $functionUseImportTypes = $this->useNodesToAddCollector->getFunctionImportsByFileInfo($smartFileInfo); + $removedShortUses = $this->useNodesToAddCollector->getShortUsesByFileInfo($smartFileInfo); // nothing to import or remove if ($useImportTypes === [] && $functionUseImportTypes === [] && $removedShortUses === []) { @@ -90,7 +86,7 @@ public function traverse(array $nodes): array /** @var FullyQualifiedObjectType[] $useImportTypes */ $useImportTypes = $this->typeFactory->uniquateTypes($useImportTypes); - $this->useNodesToAddCollector->clear($filePath); + $this->useNodesToAddCollector->clear($smartFileInfo); // A. has namespace? add under it $namespace = $this->betterNodeFinder->findFirstInstanceOf($nodes, Namespace_::class); @@ -112,32 +108,6 @@ public function traverse(array $nodes): array return $this->useImportsAdder->addImportsToStmts($nodes, $useImportTypes, $functionUseImportTypes); } - /** - * This prevents importing: - * - App\Some\Product - * - * if there is already: - * - use App\Another\Product - */ - public function canImportBeAdded(Node $node, FullyQualifiedObjectType $fullyQualifiedObjectType): bool - { - $useImportTypes = $this->useNodesToAddCollector->getUseImportTypesByNode($node); - - foreach ($useImportTypes as $useImportType) { - if (! $useImportType->equals($fullyQualifiedObjectType) && - $useImportType->areShortNamesEqual($fullyQualifiedObjectType) - ) { - return false; - } - - if ($useImportType->equals($fullyQualifiedObjectType)) { - return true; - } - } - - return true; - } - public function getPriority(): int { return 500; @@ -148,12 +118,6 @@ public function getDefinition(): RectorDefinition return new RectorDefinition('Post Rector that adds use statements'); } - public function refactor(Node $node): ?Node - { - // note: traverse() is used instead - return null; - } - /** * Prevents * @param FullyQualifiedObjectType[] $useImportTypes @@ -174,14 +138,16 @@ private function filterOutNonNamespacedNames(array $useImportTypes): array return $namespacedUseImportTypes; } - private function getRealPathFromNode(Node $node): ?string + private function getSmartFileInfo(array $nodes): ?SmartFileInfo { - /** @var SmartFileInfo|null $fileInfo */ - $fileInfo = $node->getAttribute(AttributeKey::FILE_INFO); - if ($fileInfo === null) { - return null; + foreach ($nodes as $node) { + /** @var SmartFileInfo|null $smartFileInfo */ + $smartFileInfo = $node->getAttribute(AttributeKey::FILE_INFO); + if ($smartFileInfo !== null) { + return $smartFileInfo; + } } - return $fileInfo->getRealPath(); + return null; } } diff --git a/packages/post-rector/src/Validator/CanImportBeAddedValidator.php b/packages/post-rector/src/Validator/CanImportBeAddedValidator.php new file mode 100644 index 000000000000..ee619c20d89b --- /dev/null +++ b/packages/post-rector/src/Validator/CanImportBeAddedValidator.php @@ -0,0 +1,48 @@ +useNodesToAddCollector = $useNodesToAddCollector; + } + + /** + * This prevents importing: + * - App\Some\Product + * + * if there is already: + * - use App\Another\Product + */ + public function canImportBeAdded(Node $node, FullyQualifiedObjectType $fullyQualifiedObjectType): bool + { + $useImportTypes = $this->useNodesToAddCollector->getUseImportTypesByNode($node); + + foreach ($useImportTypes as $useImportType) { + if (! $useImportType->equals($fullyQualifiedObjectType) && + $useImportType->areShortNamesEqual($fullyQualifiedObjectType) + ) { + return false; + } + + if ($useImportType->equals($fullyQualifiedObjectType)) { + return true; + } + } + + return true; + } +} diff --git a/phpstan.neon b/phpstan.neon index 6b209ad581a0..a5f06394dd28 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -219,13 +219,11 @@ parameters: - '#Parameter \#1 \$typeNode of method Rector\\StaticTypeMapper\\StaticTypeMapper\:\:mapPHPStanPhpDocTypeNodeToPHPStanType\(\) expects PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode, PHPStan\\PhpDocParser\\Ast\\Node given#' - '#Parameter \#1 \$str of function preg_quote expects string, int\|string given#' - - '#Parameter \#1 \$node of method Rector\\Core\\PhpParser\\Node\\Commander\\NodeAddingCommander\:\:wrapToExpression\(\) expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Stmt, PhpParser\\Node given#' - '#Parameter \#2 \$propertyName of method Rector\\TypeDeclaration\\TypeInferer\\PropertyTypeInferer\\SingleMethodAssignedNodePropertyTypeInferer\:\:resolveAssignedNodeToProperty\(\) expects string, string\|null given#' - '#Parameter \#1 \$sprintfFuncCall of method Rector\\Core\\PhpParser\\NodeTransformer\:\:transformSprintfToArray\(\) expects PhpParser\\Node\\Expr\\FuncCall, PhpParser\\Node given#' - '#Parameter \#1 \$nodes of method Rector\\CodeQuality\\Rector\\Array_\\CallableThisArrayToAnonymousFunctionRector\:\:hasClassMethodReturn\(\) expects array, array given#' - '#Parameter \#1 \$nodes of method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:find\(\) expects array\|PhpParser\\Node, array\|null given#' - '#PHPDoc tag @return with type iterable is not subtype of native type array#' - - '#Method Rector\\BetterPhpDocParser\\AnnotationReader\\NodeAnnotationReader\:\:createClassReflectionFromNode\(\) return type with generic class ReflectionClass does not specify its types\: T#' - '#Method Rector\\SOLID\\Reflection\\ParentConstantReflectionResolver\:\:(.*?)\(\) should return ReflectionClassConstant\|null but returns ReflectionClassConstant\|false#' - '#Parameter \#1 \$firstStmt of method Rector\\Core\\Rector\\MethodBody\\NormalToFluentRector\:\:isBothMethodCallMatch\(\) expects PhpParser\\Node\\Stmt\\Expression, PhpParser\\Node\\Stmt given#' - '#Method Rector\\Core\\Rector\\AbstractRector\:\:wrapToArg\(\) should return array but returns array#' @@ -245,8 +243,7 @@ parameters: - '#Access to an undefined property PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode\:\:\$description#' - '#Method Rector\\Php80\\Rector\\NotIdentical\\StrContainsRector\:\:matchNotIdenticalToFalse\(\) should return PhpParser\\Node\\Expr\\FuncCall\|null but returns PhpParser\\Node\\Expr#' - - '#Method Rector\\NodeCollector\\StaticAnalyzer\:\:hasStaticAnnotation\(\) has parameter \$reflectionClass with generic class ReflectionClass but does not specify its types\: T#' - - '#Parameter \#1 \$node of method Rector\\Core\\Rector\\AbstractRector\:\:isVariableName\(\) expects PhpParser\\Node, PhpParser\\Node\\Expr\|null given#' - '#Parameter \#2 \$name of method Rector\\Core\\Rector\\AbstractRector\:\:isVariableName\(\) expects string, string\|null given#' - - '#Method Rector\\PostRector\\Rector\\AbstractPostRector\:\:wrapToArg\(\) should return array but returns array#' + + - '#Parameter \#1 \$node of method Rector\\PostRector\\Collector\\NodesToAddCollector\:\:wrapToExpression\(\) expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Stmt, PhpParser\\Node given#' diff --git a/rules/coding-style/src/Imports/ImportSkipper.php b/rules/coding-style/src/Imports/ImportSkipper.php index eaf2c456575a..c846c358098f 100644 --- a/rules/coding-style/src/Imports/ImportSkipper.php +++ b/rules/coding-style/src/Imports/ImportSkipper.php @@ -7,15 +7,10 @@ use Nette\Utils\Strings; use PhpParser\Node; use Rector\PHPStan\Type\FullyQualifiedObjectType; -use Rector\PostRector\Rector\UseAddingPostRector; +use Rector\PostRector\Validator\CanImportBeAddedValidator; final class ImportSkipper { - /** - * @var UseAddingPostRector - */ - private $useAddingPostRector; - /** * @var AliasUsesResolver */ @@ -26,14 +21,19 @@ final class ImportSkipper */ private $shortNameResolver; + /** + * @var CanImportBeAddedValidator + */ + private $canImportBeAddedValidator; + public function __construct( - UseAddingPostRector $useAddingPostRector, AliasUsesResolver $aliasUsesResolver, - ShortNameResolver $shortNameResolver + ShortNameResolver $shortNameResolver, + CanImportBeAddedValidator $canImportBeAddedValidator ) { - $this->useAddingPostRector = $useAddingPostRector; $this->aliasUsesResolver = $aliasUsesResolver; $this->shortNameResolver = $shortNameResolver; + $this->canImportBeAddedValidator = $canImportBeAddedValidator; } public function shouldSkipNameForFullyQualifiedObjectType( @@ -52,7 +52,7 @@ public function shouldSkipNameForFullyQualifiedObjectType( return true; } - return ! $this->useAddingPostRector->canImportBeAdded($node, $fullyQualifiedObjectType); + return ! $this->canImportBeAddedValidator->canImportBeAdded($node, $fullyQualifiedObjectType); } private function isShortNameAlreadyUsedForDifferentFullyQualifiedName( diff --git a/rules/coding-style/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php b/rules/coding-style/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php deleted file mode 100644 index b7fadec86359..000000000000 --- a/rules/coding-style/src/Rector/Namespace_/ImportFullyQualifiedNamesRector.php +++ /dev/null @@ -1,126 +0,0 @@ -nameImporter = $nameImporter; - $this->docBlockNameImporter = $docBlockNameImporter; - } - - public function getDefinition(): RectorDefinition - { - return new RectorDefinition('Import fully qualified names to use statements', [ - new CodeSample( - <<<'PHP' -class SomeClass -{ - public function create() - { - return SomeAnother\AnotherClass; - } - - public function createDate() - { - return new \DateTime(); - } -} -PHP - , - <<<'PHP' -use SomeAnother\AnotherClass; -use DateTime; - -class SomeClass -{ - public function create() - { - return AnotherClass; - } - - public function createDate() - { - return new DateTime(); - } -} -PHP - ), - ]); - } - - /** - * @return string[] - */ - public function getNodeTypes(): array - { - return [Name::class, Node::class]; - } - - /** - * @param Name|Node $node - */ - public function refactor(Node $node): ?Node - { - // this file remains just for testing - // breaks other rectors by making name nodes short, FQN → short names - /** prevents duplicated run with @see \Rector\PostRector\Application\\Rector\PostRector\Rector\NameImportingRector */ - if (! PHPUnitEnvironment::isPHPUnitRun()) { - return null; - } - - $this->useNodesToAddCollector->analyseFileInfoUseStatements($node); - - if ($node instanceof Name) { - return $this->nameImporter->importName($node); - } - - // process doc blocks - /** @var PhpDocInfo|null $phpDocInfo */ - $phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO); - if ($phpDocInfo === null) { - return null; - } - - $hasChanged = $this->docBlockNameImporter->importNames($phpDocInfo, $node); - if (! $hasChanged) { - return null; - } - - return $node; - } -} diff --git a/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php b/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php index 817ba8556578..113615c01d4c 100644 --- a/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php +++ b/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportFullyQualifiedNamesRectorTest.php @@ -5,9 +5,13 @@ namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector; use Iterator; -use Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector; +use Rector\Core\Configuration\Option; use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase; +use Rector\Renaming\Rector\Class_\RenameClassRector; +/** + * @see \Rector\PostRector\Rector\NameImportingPostRector + */ final class ImportFullyQualifiedNamesRectorTest extends AbstractRectorTestCase { /** @@ -16,6 +20,8 @@ final class ImportFullyQualifiedNamesRectorTest extends AbstractRectorTestCase */ public function test(string $file): void { + $this->setParameter(Option::AUTO_IMPORT_NAMES, true); + $this->doTestFile($file); } @@ -37,6 +43,7 @@ public function skippedProviderPartials(): Iterator protected function getRectorClass(): string { - return ImportFullyQualifiedNamesRector::class; + // the must be any rector class to run + return RenameClassRector::class; } } diff --git a/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php b/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php index 63556b4a93bb..2aefae279d95 100644 --- a/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php +++ b/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/ImportRootNamespaceClassesDisabledTest.php @@ -4,10 +4,13 @@ namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector; -use Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector; use Rector\Core\Configuration\Option; use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase; +use Rector\Renaming\Rector\Class_\RenameClassRector; +/** + * @see \Rector\PostRector\Rector\NameImportingPostRector + */ final class ImportRootNamespaceClassesDisabledTest extends AbstractRectorTestCase { /** @@ -15,7 +18,10 @@ final class ImportRootNamespaceClassesDisabledTest extends AbstractRectorTestCas */ public function test(string $file): void { + $this->setParameter(Option::AUTO_IMPORT_NAMES, true); + $this->setParameter(Option::IMPORT_SHORT_CLASSES_PARAMETER, false); + $this->doTestFile($file); } @@ -26,6 +32,7 @@ public function provideData(): iterable protected function getRectorClass(): string { - return ImportFullyQualifiedNamesRector::class; + // the must be any rector class to run + return RenameClassRector::class; } } diff --git a/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/NonNamespacedTest.php b/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/NonNamespacedTest.php index 38c9a3322f07..08f4011aa332 100644 --- a/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/NonNamespacedTest.php +++ b/rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/NonNamespacedTest.php @@ -5,9 +5,13 @@ namespace Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector; use Iterator; -use Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector; +use Rector\Core\Configuration\Option; use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase; +use Rector\Renaming\Rector\Class_\RenameClassRector; +/** + * @see \Rector\PostRector\Rector\NameImportingPostRector + */ final class NonNamespacedTest extends AbstractRectorTestCase { /** @@ -15,6 +19,8 @@ final class NonNamespacedTest extends AbstractRectorTestCase */ public function test(string $file): void { + $this->setParameter(Option::AUTO_IMPORT_NAMES, true); + $this->doTestFile($file); } @@ -25,6 +31,6 @@ public function provideData(): Iterator protected function getRectorClass(): string { - return ImportFullyQualifiedNamesRector::class; + return RenameClassRector::class; } } diff --git a/rules/nette-tester-to-phpunit/src/AssertManipulator.php b/rules/nette-tester-to-phpunit/src/AssertManipulator.php index 79b63217258b..78a7d891f437 100644 --- a/rules/nette-tester-to-phpunit/src/AssertManipulator.php +++ b/rules/nette-tester-to-phpunit/src/AssertManipulator.php @@ -18,12 +18,12 @@ use PHPStan\Type\BooleanType; use Prophecy\Doubler\Generator\Node\MethodNode; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; -use Rector\Core\PhpParser\Node\Commander\NodeAddingCommander; use Rector\Core\PhpParser\Node\Value\ValueResolver; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; use Rector\NodeTypeResolver\TypeAnalyzer\StringTypeAnalyzer; +use Rector\PostRector\Collector\NodesToAddCollector; use Rector\PostRector\Collector\NodesToRemoveCollector; final class AssertManipulator @@ -81,11 +81,6 @@ final class AssertManipulator */ private $valueResolver; - /** - * @var NodeAddingCommander - */ - private $nodeAddingCommander; - /** * @var StringTypeAnalyzer */ @@ -96,20 +91,25 @@ final class AssertManipulator */ private $nodesToRemoveCollector; + /** + * @var NodesToAddCollector + */ + private $nodesToAddCollector; + public function __construct( NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, ValueResolver $valueResolver, - NodeAddingCommander $nodeAddingCommander, + NodesToAddCollector $nodesToAddCollector, NodesToRemoveCollector $nodesToRemoveCollector, StringTypeAnalyzer $stringTypeAnalyzer ) { $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; $this->valueResolver = $valueResolver; - $this->nodeAddingCommander = $nodeAddingCommander; $this->stringTypeAnalyzer = $stringTypeAnalyzer; $this->nodesToRemoveCollector = $nodesToRemoveCollector; + $this->nodesToAddCollector = $nodesToAddCollector; } /** @@ -178,7 +178,7 @@ private function processExceptionCall(StaticCall $staticCall): void } $expectException->args[] = $staticCall->args[1]; - $this->nodeAddingCommander->addNodeAfterNode($expectException, $staticCall); + $this->nodesToAddCollector->addNodeAfterNode($expectException, $staticCall); // expect message if (isset($staticCall->args[2])) { @@ -193,7 +193,7 @@ private function processExceptionCall(StaticCall $staticCall): void /** @var Closure $closure */ $closure = $staticCall->args[0]->value; foreach ((array) $closure->stmts as $callableStmt) { - $this->nodeAddingCommander->addNodeAfterNode($callableStmt, $staticCall); + $this->nodesToAddCollector->addNodeAfterNode($callableStmt, $staticCall); } $this->nodesToRemoveCollector->addNodeToRemove($staticCall); @@ -222,7 +222,7 @@ private function processNoErrorCall(StaticCall $staticCall): void $closure = $staticCall->args[0]->value; foreach ((array) $closure->stmts as $callableStmt) { - $this->nodeAddingCommander->addNodeAfterNode($callableStmt, $staticCall); + $this->nodesToAddCollector->addNodeAfterNode($callableStmt, $staticCall); } $this->nodesToRemoveCollector->addNodeToRemove($staticCall); @@ -278,7 +278,7 @@ private function refactorExpectException(StaticCall $staticCall): string } $expectExceptionMessage->args[] = $staticCall->args[2]; - $this->nodeAddingCommander->addNodeAfterNode($expectExceptionMessage, $staticCall); + $this->nodesToAddCollector->addNodeAfterNode($expectExceptionMessage, $staticCall); return $method; } @@ -293,7 +293,7 @@ private function refactorExpectExceptionCode(StaticCall $staticCall): void } $expectExceptionCode->args[] = $staticCall->args[3]; - $this->nodeAddingCommander->addNodeAfterNode($expectExceptionCode, $staticCall); + $this->nodesToAddCollector->addNodeAfterNode($expectExceptionCode, $staticCall); } private function renameAssertMethod(StaticCall $staticCall): void diff --git a/rules/renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php b/rules/renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php index 6a980f8a5690..84ce81fb85b0 100644 --- a/rules/renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php +++ b/rules/renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php @@ -6,13 +6,14 @@ use Iterator; use Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector; +use Rector\Core\Configuration\Option; use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase; use Rector\Renaming\Rector\Class_\RenameClassRector; use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\NewClass; use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\OldClass; /** - * @see \Rector\PostRector\Rector\NameImportingRector + * @see \Rector\PostRector\Rector\NameImportingPostRector */ final class AutoImportNamesParameterTest extends AbstractRectorTestCase { @@ -21,6 +22,8 @@ final class AutoImportNamesParameterTest extends AbstractRectorTestCase */ public function test(string $filePath): void { + $this->setParameter(Option::AUTO_IMPORT_NAMES, true); + $this->doTestFile($filePath); } @@ -29,11 +32,6 @@ public function provideData(): Iterator return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureAutoImportNames'); } - protected function getAutoImportNames(): ?bool - { - return true; - } - /** * @return mixed[] */ diff --git a/rules/renaming/tests/Rector/Class_/RenameClassRector/FunctionAutoImportNamesParameterTest.php b/rules/renaming/tests/Rector/Class_/RenameClassRector/FunctionAutoImportNamesParameterTest.php index 863c3bb9e6c2..d6da5bc734fe 100644 --- a/rules/renaming/tests/Rector/Class_/RenameClassRector/FunctionAutoImportNamesParameterTest.php +++ b/rules/renaming/tests/Rector/Class_/RenameClassRector/FunctionAutoImportNamesParameterTest.php @@ -5,13 +5,14 @@ namespace Rector\Renaming\Tests\Rector\Class_\RenameClassRector; use Iterator; +use Rector\Core\Configuration\Option; use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase; use Rector\Renaming\Rector\Class_\RenameClassRector; use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\NewClass; use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\OldClass; /** - * @see \Rector\PostRector\Rector\NameImportingRector + * @see \Rector\PostRector\Rector\NameImportingPostRector */ final class FunctionAutoImportNamesParameterTest extends AbstractRectorTestCase { @@ -20,6 +21,8 @@ final class FunctionAutoImportNamesParameterTest extends AbstractRectorTestCase */ public function test(string $filePath): void { + $this->setParameter(Option::AUTO_IMPORT_NAMES, true); + $this->doTestFile($filePath); } @@ -28,11 +31,6 @@ public function provideData(): Iterator return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureAutoImportNamesFunction'); } - protected function getAutoImportNames(): ?bool - { - return true; - } - /** * @return mixed[] */ diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php index 3e780d53ae85..7cf71ace7854 100644 --- a/src/Application/FileProcessor.php +++ b/src/Application/FileProcessor.php @@ -135,12 +135,13 @@ public function printToString(SmartFileInfo $smartFileInfo): string public function refactor(SmartFileInfo $smartFileInfo): void { $this->stubLoader->loadStubs(); + $this->currentFileInfoProvider->setCurrentFileInfo($smartFileInfo); $this->makeSureFileIsParsed($smartFileInfo); [$newStmts, $oldStmts, $oldTokens] = $this->tokensByFilePath[$smartFileInfo->getRealPath()]; $newStmts = $this->rectorNodeTraverser->traverse($newStmts); - $newStmts = $this->postFileProcessor->traverseNodes($newStmts); + $newStmts = $this->postFileProcessor->traverse($newStmts); // this is needed for new tokens added in "afterTraverse()" $this->tokensByFilePath[$smartFileInfo->getRealPath()] = [$newStmts, $oldStmts, $oldTokens]; diff --git a/src/Contract/PhpParser/Node/CommanderInterface.php b/src/Contract/PhpParser/Node/CommanderInterface.php deleted file mode 100644 index c32e32f634c9..000000000000 --- a/src/Contract/PhpParser/Node/CommanderInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -someCall(); - * - * To: - * - $this->someCall(); - * - $value = this->someNewCall(); // added expression - */ -final class NodeAddingCommander implements CommanderInterface -{ - /** - * @var Stmt[][] - */ - private $nodesToAdd = []; - - /** - * @var Stmt[][] - */ - private $nodesToAddBefore = []; - - /** - * @var BetterNodeFinder - */ - private $betterNodeFinder; - - public function __construct(BetterNodeFinder $betterNodeFinder) - { - $this->betterNodeFinder = $betterNodeFinder; - } - - public function addNodeBeforeNode(Node $addedNode, Node $positionNode): void - { - $position = $this->resolveNearestExpressionPosition($positionNode); - - $this->nodesToAddBefore[$position][] = $this->wrapToExpression($addedNode); - } - - public function addNodeAfterNode(Node $addedNode, Node $positionNode): void - { - $position = $this->resolveNearestExpressionPosition($positionNode); - - $this->nodesToAdd[$position][] = $this->wrapToExpression($addedNode); - } - - /** - * @param Node[] $nodes - * @return Node[] - */ - public function traverseNodes(array $nodes): array - { - $nodeTraverser = new NodeTraverser(); - $nodeTraverser->addVisitor($this->createNodeVisitor()); - - // new nodes to remove are always per traverse - $this->reset(); - - return $nodeTraverser->traverse($nodes); - } - - public function isActive(): bool - { - return count($this->nodesToAdd) > 0 || count($this->nodesToAddBefore) > 0; - } - - public function getPriority(): int - { - return 1000; - } - - private function resolveNearestExpressionPosition(Node $node): string - { - if ($node instanceof Expression) { - return spl_object_hash($node); - } - - // special case for "If_" - if ($node instanceof If_) { - return spl_object_hash($node); - } - - /** @var Expression|null $foundNode */ - $foundNode = $this->betterNodeFinder->findFirstAncestorInstanceOf($node, Expression::class); - if ($foundNode === null) { - $foundNode = $node; - } - - return spl_object_hash($foundNode); - } - - /** - * @param Expr|Stmt $node - */ - private function wrapToExpression(Node $node): Stmt - { - return $node instanceof Stmt ? $node : new Expression($node); - } - - private function createNodeVisitor(): NodeVisitor - { - return new class($this->nodesToAdd, $this->nodesToAddBefore) extends NodeVisitorAbstract { - /** - * @var Stmt[][] - */ - private $nodesToAdd = []; - - /** - * @var Stmt[][] - */ - private $nodesToAddBefore = []; - - /** - * @param Stmt[][] $nodesToAdd - * @param Stmt[][] $nodesToAddBefore - */ - public function __construct(array $nodesToAdd, array $nodesToAddBefore) - { - $this->nodesToAdd = $nodesToAdd; - $this->nodesToAddBefore = $nodesToAddBefore; - } - - /** - * @return Node[]|Node|null - */ - public function leaveNode(Node $node) - { - $position = spl_object_hash($node); - - // add node after - if (isset($this->nodesToAdd[$position])) { - $nodes = array_merge([$node], $this->nodesToAdd[$position]); - unset($this->nodesToAdd[$position]); - return $nodes; - } - - // add node before - if (isset($this->nodesToAddBefore[$position])) { - $nodes = array_merge($this->nodesToAddBefore[$position], [$node]); - - unset($this->nodesToAddBefore[$position]); - - return $nodes; - } - - return null; - } - }; - } - - private function reset(): void - { - $this->nodesToAdd = []; - $this->nodesToAddBefore = []; - } -} diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index c57f1654d194..dd607bec3a50 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -317,10 +317,6 @@ protected function unwrapStmts(array $stmts, Node $node): void private function isNameIdentical(Node $node, Node $originalNode): bool { - if (static::class !== ImportFullyQualifiedNamesRector::class) { - return false; - } - if (! $originalNode instanceof Name) { return false; } diff --git a/src/Testing/PHPUnit/AbstractGenericRectorTestCase.php b/src/Testing/PHPUnit/AbstractGenericRectorTestCase.php index 55a338306c40..1f2dabb09fea 100644 --- a/src/Testing/PHPUnit/AbstractGenericRectorTestCase.php +++ b/src/Testing/PHPUnit/AbstractGenericRectorTestCase.php @@ -76,7 +76,7 @@ protected function setParameter(string $name, $value): void { $parameterProvider = self::$container->get(ParameterProvider::class); - if (! in_array($name, [Option::PHP_VERSION_FEATURES, Option::AUTO_IMPORT_NAMES], true)) { + if ($name !== Option::PHP_VERSION_FEATURES) { $oldParameterValue = $parameterProvider->provideParameter($name); $this->oldParameterValues[$name] = $oldParameterValue; } diff --git a/src/Testing/PHPUnit/AbstractRectorTestCase.php b/src/Testing/PHPUnit/AbstractRectorTestCase.php index 6a61eb2e15e4..74fb7685938c 100644 --- a/src/Testing/PHPUnit/AbstractRectorTestCase.php +++ b/src/Testing/PHPUnit/AbstractRectorTestCase.php @@ -105,7 +105,6 @@ protected function setUp(): void $stubLoader->loadStubs(); $this->configurePhpVersionFeatures(); - $this->configureAutoImportParameter(); } protected function tearDown(): void @@ -116,11 +115,6 @@ protected function tearDown(): void if ($this->getPhpVersion() !== '') { $this->setParameter(Option::PHP_VERSION_FEATURES, '10.0'); } - - // restore disabled auto_import_names if changed - if ($this->getAutoImportNames() !== null) { - $this->setParameter(Option::AUTO_IMPORT_NAMES, false); - } } protected function doTestFileWithoutAutoload(string $file): void @@ -164,12 +158,6 @@ protected function getRectorInterface(): string return PhpRectorInterface::class; } - protected function getAutoImportNames(): ?bool - { - // to be implemented - return null; - } - protected function doTestExtraFile(string $expectedExtraFileName, string $expectedExtraContentFilePath): void { $expectedFilePath = sys_get_temp_dir() . '/rector_temp_tests/' . $expectedExtraFileName; @@ -248,17 +236,6 @@ private function configurePhpVersionFeatures(): void $this->setParameter(Option::PHP_VERSION_FEATURES, $this->getPhpVersion()); } - private function configureAutoImportParameter(): void - { - // for faster tests - $autoImportNames = false; - if ($this->getAutoImportNames() !== null) { - $autoImportNames = $this->getAutoImportNames(); - } - - $this->parameterProvider->changeParameter(Option::AUTO_IMPORT_NAMES, $autoImportNames); - } - private function doTestFileMatchesExpectedContent( string $originalFile, string $expectedFile,