move node adding to PostRector

This commit is contained in:
TomasVotruba 2020-03-31 20:46:33 +02:00
parent 5957c03cb5
commit 5600cf8d4d
30 changed files with 347 additions and 633 deletions

View File

@ -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

View File

@ -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)

View File

@ -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;
}
}

View 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);
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;

View 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');
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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#'

View File

@ -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(

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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[]
*/

View File

@ -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[]
*/

View File

@ -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];

View File

@ -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;
}

View File

@ -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 = [];
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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,