Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion config/set/coding-style/coding-style.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 10 additions & 31 deletions docs/AllRectorsOverview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
104 changes: 20 additions & 84 deletions packages/post-rector/src/Application/PostFileProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,120 +6,56 @@

use PhpParser\Node;
use PhpParser\NodeTraverser;
use Rector\Core\Contract\PhpParser\Node\CommanderInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\FileSystem\CurrentFileInfoProvider;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PostRector\Contract\Rector\PostRectorInterface;
use Rector\PostRector\Rector\UseAddingPostRector;
use Symplify\SmartFileSystem\SmartFileInfo;

final class PostFileProcessor extends NodeTraverser
final class PostFileProcessor
{
/**
* @var CommanderInterface[]|PostRectorInterface[]
* @var PostRectorInterface[]
*/
private $commanders = [];
private $postRectors = [];

/**
* @var CurrentFileInfoProvider
*/
private $currentFileInfoProvider;

/**
* @var UseAddingPostRector
*/
private $useAddingPostRector;

/**
* @param CommanderInterface[] $commanders
* @param PostRectorInterface[] $postRectors
*/
public function __construct(
CurrentFileInfoProvider $currentFileInfoProvider,
array $commanders,
array $postRectors,
UseAddingPostRector $useAddingPostRector
) {
// A. slowly remove...
$commanders = array_merge($commanders, $postRectors);

$this->sortByPriorityAndSetCommanders($commanders);
$this->currentFileInfoProvider = $currentFileInfoProvider;

// B. refactor into ↓
foreach ($commanders as $commander) {
if ($commander instanceof PostRectorInterface) {
$this->addVisitor($commander);
}
}

$this->useAddingPostRector = $useAddingPostRector;
public function __construct(array $postRectors)
{
$this->sortByPriorityAndSetCommanders($postRectors);
}

/**
* @param Node[] $nodes
* @return Node[]
*/
public function traverseNodes(array $nodes): array
public function traverse(array $nodes): array
{
$this->setCurrentFileInfo($nodes);

// A. commanders
foreach ($this->commanders as $commander) {
if (! $commander instanceof CommanderInterface) {
continue;
}

if (! $commander->isActive()) {
continue;
}

$nodes = $commander->traverseNodes($nodes);
foreach ($this->postRectors as $postRector) {
$nodeTraverser = new NodeTraverser();
$nodeTraverser->addVisitor($postRector);
$nodes = $nodeTraverser->traverse($nodes);
}

// B. post rectors
$nodes = parent::traverse($nodes);

// must run standalone, after NameImporitngPostRector, so it won't skip TraverseNodes()

return $this->useAddingPostRector->traverse($nodes);
return $nodes;
}

/**
* @param CommanderInterface[]|PostRectorInterface[] $commanders
* @param PostRectorInterface[] $postRectors
*/
private function sortByPriorityAndSetCommanders(array $commanders): void
private function sortByPriorityAndSetCommanders(array $postRectors): void
{
$commandersByPriority = [];
$postRectorsByPriority = [];

foreach ($commanders as $commander) {
if (isset($commandersByPriority[$commander->getPriority()])) {
foreach ($postRectors as $postRector) {
if (isset($postRectorsByPriority[$postRector->getPriority()])) {
throw new ShouldNotHappenException();
}

$commandersByPriority[$commander->getPriority()] = $commander;
$postRectorsByPriority[$postRector->getPriority()] = $postRector;
}

krsort($commandersByPriority);

$this->commanders = $commandersByPriority;
}

/**
* @param Node[] $nodes
*/
private function setCurrentFileInfo(array $nodes): void
{
foreach ($nodes as $node) {
/** @var SmartFileInfo|null $fileInfo */
$fileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
if (! $fileInfo instanceof SmartFileInfo) {
continue;
}
krsort($postRectorsByPriority);

$this->currentFileInfoProvider->setCurrentFileInfo($fileInfo);
break;
}
$this->postRectors = $postRectorsByPriority;
}
}
105 changes: 105 additions & 0 deletions packages/post-rector/src/Collector/NodesToAddCollector.php
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading