mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-21 18:42:24 +00:00
move node adding to PostRector
This commit is contained in:
parent
5957c03cb5
commit
5600cf8d4d
|
@ -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
|
||||
|
|
|
@ -2075,35 +2075,6 @@ Changes === false to negate !
|
|||
|
||||
<br>
|
||||
|
||||
### `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();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### `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
|
||||
|
||||
<br>
|
||||
|
||||
### `NodeAddingPostRector`
|
||||
|
||||
- class: [`Rector\PostRector\Rector\NodeAddingPostRector`](/../master/packages/post-rector/src/Rector/NodeAddingPostRector.php)
|
||||
|
||||
Post Rector that adds nodes
|
||||
|
||||
<br>
|
||||
|
||||
### `NodeRemovingRector`
|
||||
|
||||
- class: [`Rector\PostRector\Rector\NodeRemovingRector`](/../master/packages/post-rector/src/Rector/NodeRemovingRector.php)
|
||||
|
|
|
@ -6,120 +6,56 @@ namespace Rector\PostRector\Application;
|
|||
|
||||
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);
|
||||
krsort($postRectorsByPriority);
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
$this->currentFileInfoProvider->setCurrentFileInfo($fileInfo);
|
||||
break;
|
||||
}
|
||||
$this->postRectors = $postRectorsByPriority;
|
||||
}
|
||||
}
|
||||
|
|
105
packages/post-rector/src/Collector/NodesToAddCollector.php
Normal file
105
packages/post-rector/src/Collector/NodesToAddCollector.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PostRector\Collector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\PostRector\Contract\Collector\NodeCollectorInterface;
|
||||
|
||||
final class NodesToAddCollector implements NodeCollectorInterface
|
||||
{
|
||||
/**
|
||||
* @var Stmt[][]
|
||||
*/
|
||||
private $nodesToAddAfter = [];
|
||||
|
||||
/**
|
||||
* @var Stmt[][]
|
||||
*/
|
||||
private $nodesToAddBefore = [];
|
||||
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
public function __construct(BetterNodeFinder $betterNodeFinder)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ namespace Rector\PostRector\Collector;
|
|||
|
||||
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 @@ final class UseNodesToAddCollector implements NodeCollectorInterface
|
|||
$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 @@ final class UseNodesToAddCollector implements NodeCollectorInterface
|
|||
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 @@ final class UseNodesToAddCollector implements NodeCollectorInterface
|
|||
/**
|
||||
* @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
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
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 @@ use Rector\PostRector\Contract\Rector\PostRectorInterface;
|
|||
abstract class AbstractPostRector extends NodeVisitorAbstract implements PostRectorInterface
|
||||
{
|
||||
use NameResolverTrait;
|
||||
|
||||
/**
|
||||
* @return int|Node|null
|
||||
*/
|
||||
final public function enterNode(Node $node)
|
||||
{
|
||||
return $this->refactor($node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ use PhpParser\Node\Stmt\ClassLike;
|
|||
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 @@ trait NodeCommandersTrait
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
|||
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 @@ final class NameImportingRector extends AbstractPostRector
|
|||
$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;
|
64
packages/post-rector/src/Rector/NodeAddingPostRector.php
Normal file
64
packages/post-rector/src/Rector/NodeAddingPostRector.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PostRector\Rector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\PostRector\Collector\NodesToAddCollector;
|
||||
|
||||
/**
|
||||
* This class collects all to-be-added expresssions (= 1 line in code)
|
||||
* and then adds new expressions to list of $nodes
|
||||
*
|
||||
* From:
|
||||
* - $this->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');
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@ final class NodeRemovingRector extends AbstractPostRector
|
|||
return 800;
|
||||
}
|
||||
|
||||
public function refactor(Node $node): ?Node
|
||||
public function enterNode(Node $node): ?Node
|
||||
{
|
||||
if (! $this->nodesToRemoveCollector->isActive()) {
|
||||
return null;
|
||||
|
|
|
@ -25,13 +25,6 @@ final class NodeToReplacePostRector extends AbstractPostRector
|
|||
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 @@ final class NodeToReplacePostRector extends AbstractPostRector
|
|||
return $replacement;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ final class PropertyAddingPostRector extends AbstractPostRector
|
|||
return 900;
|
||||
}
|
||||
|
||||
public function refactor(Node $node): ?Node
|
||||
public function enterNode(Node $node): ?Node
|
||||
{
|
||||
if (! $node instanceof Class_ || $node->isAnonymous()) {
|
||||
return null;
|
||||
|
|
|
@ -5,13 +5,10 @@ declare(strict_types=1);
|
|||
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\PHPStan\Type\FullyQualifiedObjectType;
|
|||
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 @@ final class UseAddingPostRector extends NodeVisitorAbstract implements RectorInt
|
|||
* @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 @@ final class UseAddingPostRector extends NodeVisitorAbstract implements RectorInt
|
|||
/** @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 @@ final class UseAddingPostRector extends NodeVisitorAbstract implements RectorInt
|
|||
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 @@ final class UseAddingPostRector extends NodeVisitorAbstract implements RectorInt
|
|||
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 @@ final class UseAddingPostRector extends NodeVisitorAbstract implements RectorInt
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PostRector\Validator;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Rector\PHPStan\Type\FullyQualifiedObjectType;
|
||||
use Rector\PostRector\Collector\UseNodesToAddCollector;
|
||||
|
||||
final class CanImportBeAddedValidator
|
||||
{
|
||||
/**
|
||||
* @var UseNodesToAddCollector
|
||||
*/
|
||||
private $useNodesToAddCollector;
|
||||
|
||||
public function __construct(UseNodesToAddCollector $useNodesToAddCollector)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
|
@ -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<PhpParser\\Node\\Stmt\\Return_\>, array<PhpParser\\Node\> given#'
|
||||
- '#Parameter \#1 \$nodes of method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:find\(\) expects array<PhpParser\\Node\>\|PhpParser\\Node, array<PhpParser\\Node\\Stmt\>\|null given#'
|
||||
- '#PHPDoc tag @return with type iterable<object\> 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<PhpParser\\Node\\Arg\> but returns array<PhpParser\\Node\\Arg\|PhpParser\\Node\\Expr\>#'
|
||||
|
@ -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<PhpParser\\Node\\Arg\> but returns array<PhpParser\\Node\\Arg\|PhpParser\\Node\\Expr\>#'
|
||||
|
||||
- '#Parameter \#1 \$node of method Rector\\PostRector\\Collector\\NodesToAddCollector\:\:wrapToExpression\(\) expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Stmt, PhpParser\\Node given#'
|
||||
|
|
|
@ -7,15 +7,10 @@ namespace Rector\CodingStyle\Imports;
|
|||
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 @@ final class ImportSkipper
|
|||
return true;
|
||||
}
|
||||
|
||||
return ! $this->useAddingPostRector->canImportBeAdded($node, $fullyQualifiedObjectType);
|
||||
return ! $this->canImportBeAddedValidator->canImportBeAdded($node, $fullyQualifiedObjectType);
|
||||
}
|
||||
|
||||
private function isShortNameAlreadyUsedForDifferentFullyQualifiedName(
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Rector\Namespace_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\CodingStyle\Node\NameImporter;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\Core\Testing\PHPUnit\PHPUnitEnvironment;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockNameImporter;
|
||||
|
||||
/**
|
||||
* This rule must be last, as it shortens nodes before using them by other Rectors, thus breaking them.
|
||||
*
|
||||
* This file remains just for testing.
|
||||
* Breaks other rectors by making name nodes short, FQN → short names
|
||||
*
|
||||
* @see \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\ImportFullyQualifiedNamesRectorTest
|
||||
* @see \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\NonNamespacedTest
|
||||
* @see \Rector\CodingStyle\Tests\Rector\Namespace_\ImportFullyQualifiedNamesRector\ImportRootNamespaceClassesDisabledTest
|
||||
*/
|
||||
final class ImportFullyQualifiedNamesRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var NameImporter
|
||||
*/
|
||||
private $nameImporter;
|
||||
|
||||
/**
|
||||
* @var DocBlockNameImporter
|
||||
*/
|
||||
private $docBlockNameImporter;
|
||||
|
||||
public function __construct(NameImporter $nameImporter, DocBlockNameImporter $docBlockNameImporter)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
|
@ -5,9 +5,13 @@ declare(strict_types=1);
|
|||
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 @@ final class ImportFullyQualifiedNamesRectorTest extends AbstractRectorTestCase
|
|||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return ImportFullyQualifiedNamesRector::class;
|
||||
// the must be any rector class to run
|
||||
return RenameClassRector::class;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
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 @@ final class ImportRootNamespaceClassesDisabledTest extends AbstractRectorTestCas
|
|||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return ImportFullyQualifiedNamesRector::class;
|
||||
// the must be any rector class to run
|
||||
return RenameClassRector::class;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,13 @@ declare(strict_types=1);
|
|||
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 @@ final class NonNamespacedTest extends AbstractRectorTestCase
|
|||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return ImportFullyQualifiedNamesRector::class;
|
||||
return RenameClassRector::class;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ use PhpParser\Node\Stmt\ClassMethod;
|
|||
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 @@ final class AssertManipulator
|
|||
}
|
||||
|
||||
$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 @@ final class AssertManipulator
|
|||
/** @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 @@ final class AssertManipulator
|
|||
$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 @@ final class AssertManipulator
|
|||
}
|
||||
|
||||
$expectExceptionMessage->args[] = $staticCall->args[2];
|
||||
$this->nodeAddingCommander->addNodeAfterNode($expectExceptionMessage, $staticCall);
|
||||
$this->nodesToAddCollector->addNodeAfterNode($expectExceptionMessage, $staticCall);
|
||||
return $method;
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,7 @@ final class AssertManipulator
|
|||
}
|
||||
|
||||
$expectExceptionCode->args[] = $staticCall->args[3];
|
||||
$this->nodeAddingCommander->addNodeAfterNode($expectExceptionCode, $staticCall);
|
||||
$this->nodesToAddCollector->addNodeAfterNode($expectExceptionCode, $staticCall);
|
||||
}
|
||||
|
||||
private function renameAssertMethod(StaticCall $staticCall): void
|
||||
|
|
|
@ -6,13 +6,14 @@ namespace Rector\Renaming\Tests\Rector\Class_\RenameClassRector;
|
|||
|
||||
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 @@ final class AutoImportNamesParameterTest extends AbstractRectorTestCase
|
|||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureAutoImportNames');
|
||||
}
|
||||
|
||||
protected function getAutoImportNames(): ?bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
|
|
|
@ -5,13 +5,14 @@ declare(strict_types=1);
|
|||
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 @@ final class FunctionAutoImportNamesParameterTest extends AbstractRectorTestCase
|
|||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureAutoImportNamesFunction');
|
||||
}
|
||||
|
||||
protected function getAutoImportNames(): ?bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
|
|
|
@ -135,12 +135,13 @@ final class FileProcessor
|
|||
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];
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\Contract\PhpParser\Node;
|
||||
|
||||
use PhpParser\Node;
|
||||
|
||||
interface CommanderInterface
|
||||
{
|
||||
/**
|
||||
* Higher values are executed first
|
||||
*/
|
||||
public function getPriority(): int;
|
||||
|
||||
public function isActive(): bool;
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @return Node[]
|
||||
*/
|
||||
public function traverseNodes(array $nodes): array;
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\PhpParser\Node\Commander;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitor;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use Rector\Core\Contract\PhpParser\Node\CommanderInterface;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
|
||||
/**
|
||||
* This class collects all to-be-added expresssions (= 1 line in code)
|
||||
* and then adds new expressions to list of $nodes
|
||||
*
|
||||
* From:
|
||||
* - $this->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 = [];
|
||||
}
|
||||
}
|
|
@ -317,10 +317,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
|||
|
||||
private function isNameIdentical(Node $node, Node $originalNode): bool
|
||||
{
|
||||
if (static::class !== ImportFullyQualifiedNamesRector::class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $originalNode instanceof Name) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ abstract class AbstractGenericRectorTestCase extends AbstractKernelTestCase
|
|||
{
|
||||
$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;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,6 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
|
|||
$stubLoader->loadStubs();
|
||||
|
||||
$this->configurePhpVersionFeatures();
|
||||
$this->configureAutoImportParameter();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
|
@ -116,11 +115,6 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
|
|||
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 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
|
|||
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 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
|
|||
$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,
|
||||
|
|
Loading…
Reference in New Issue
Block a user