mirror of
https://github.com/rectorphp/rector.git
synced 2024-07-30 21:30:23 +00:00
3266f22182
1d409bc35b
safe by default
152 lines
6.0 KiB
PHP
152 lines
6.0 KiB
PHP
<?php
|
|
|
|
declare (strict_types=1);
|
|
namespace Rector\PostRector\Rector;
|
|
|
|
use PhpParser\Node\Stmt;
|
|
use PhpParser\Node\Stmt\Namespace_;
|
|
use Rector\CodingStyle\Application\UseImportsAdder;
|
|
use Rector\CodingStyle\Application\UseImportsRemover;
|
|
use Rector\Core\Configuration\RenamedClassesDataCollector;
|
|
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
|
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
|
use Rector\Core\Provider\CurrentFileProvider;
|
|
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
|
use Rector\PostRector\Collector\UseNodesToAddCollector;
|
|
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
|
|
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
|
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
|
final class UseAddingPostRector extends \Rector\PostRector\Rector\AbstractPostRector
|
|
{
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
|
|
*/
|
|
private $betterNodeFinder;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
|
|
*/
|
|
private $typeFactory;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\CodingStyle\Application\UseImportsAdder
|
|
*/
|
|
private $useImportsAdder;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\CodingStyle\Application\UseImportsRemover
|
|
*/
|
|
private $useImportsRemover;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\PostRector\Collector\UseNodesToAddCollector
|
|
*/
|
|
private $useNodesToAddCollector;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\Core\Provider\CurrentFileProvider
|
|
*/
|
|
private $currentFileProvider;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\Core\Configuration\RenamedClassesDataCollector
|
|
*/
|
|
private $renamedClassesDataCollector;
|
|
public function __construct(\Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory $typeFactory, \Rector\CodingStyle\Application\UseImportsAdder $useImportsAdder, \Rector\CodingStyle\Application\UseImportsRemover $useImportsRemover, \Rector\PostRector\Collector\UseNodesToAddCollector $useNodesToAddCollector, \Rector\Core\Provider\CurrentFileProvider $currentFileProvider, \Rector\Core\Configuration\RenamedClassesDataCollector $renamedClassesDataCollector)
|
|
{
|
|
$this->betterNodeFinder = $betterNodeFinder;
|
|
$this->typeFactory = $typeFactory;
|
|
$this->useImportsAdder = $useImportsAdder;
|
|
$this->useImportsRemover = $useImportsRemover;
|
|
$this->useNodesToAddCollector = $useNodesToAddCollector;
|
|
$this->currentFileProvider = $currentFileProvider;
|
|
$this->renamedClassesDataCollector = $renamedClassesDataCollector;
|
|
}
|
|
/**
|
|
* @param Stmt[] $nodes
|
|
* @return Stmt[]
|
|
*/
|
|
public function beforeTraverse(array $nodes) : ?array
|
|
{
|
|
// no nodes → just return
|
|
if ($nodes === []) {
|
|
return $nodes;
|
|
}
|
|
$file = $this->currentFileProvider->getFile();
|
|
$smartFileInfo = $file->getSmartFileInfo();
|
|
$useImportTypes = $this->useNodesToAddCollector->getObjectImportsByFileInfo($smartFileInfo);
|
|
$functionUseImportTypes = $this->useNodesToAddCollector->getFunctionImportsByFileInfo($smartFileInfo);
|
|
$oldToNewClasses = $this->renamedClassesDataCollector->getOldToNewClasses();
|
|
// nothing to import or remove
|
|
if ($useImportTypes === [] && $functionUseImportTypes === [] && $oldToNewClasses === []) {
|
|
return $nodes;
|
|
}
|
|
/** @var FullyQualifiedObjectType[] $useImportTypes */
|
|
$useImportTypes = $this->typeFactory->uniquateTypes($useImportTypes);
|
|
// A. has namespace? add under it
|
|
$namespace = $this->betterNodeFinder->findFirstInstanceOf($nodes, \PhpParser\Node\Stmt\Namespace_::class);
|
|
if ($namespace instanceof \PhpParser\Node\Stmt\Namespace_) {
|
|
// first clean
|
|
//$this->useImportsRemover->removeImportsFromNamespace($namespace, $removedShortUses);
|
|
// then add, to prevent adding + removing false positive of same short use
|
|
$this->useImportsAdder->addImportsToNamespace($namespace, $useImportTypes, $functionUseImportTypes);
|
|
return $nodes;
|
|
}
|
|
$firstNode = $nodes[0];
|
|
if ($firstNode instanceof \Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace) {
|
|
$nodes = $firstNode->stmts;
|
|
}
|
|
$removedShortUses = $this->renamedClassesDataCollector->getOldClasses();
|
|
// B. no namespace? add in the top
|
|
// first clean
|
|
$nodes = $this->useImportsRemover->removeImportsFromStmts($nodes, $removedShortUses);
|
|
$useImportTypes = $this->filterOutNonNamespacedNames($useImportTypes);
|
|
// then add, to prevent adding + removing false positive of same short use
|
|
return $this->useImportsAdder->addImportsToStmts($nodes, $useImportTypes, $functionUseImportTypes);
|
|
}
|
|
public function getPriority() : int
|
|
{
|
|
// must be after name importing
|
|
return 500;
|
|
}
|
|
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
|
|
{
|
|
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition('Add unique use imports collected during Rector run', [new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample(<<<'CODE_SAMPLE'
|
|
class SomeClass
|
|
{
|
|
public function run(AnotherClass $anotherClass)
|
|
{
|
|
}
|
|
}
|
|
CODE_SAMPLE
|
|
, <<<'CODE_SAMPLE'
|
|
use App\AnotherClass;
|
|
|
|
class SomeClass
|
|
{
|
|
public function run(AnotherClass $anotherClass)
|
|
{
|
|
}
|
|
}
|
|
CODE_SAMPLE
|
|
)]);
|
|
}
|
|
/**
|
|
* Prevents
|
|
* @param FullyQualifiedObjectType[] $useImportTypes
|
|
* @return FullyQualifiedObjectType[]
|
|
*/
|
|
private function filterOutNonNamespacedNames(array $useImportTypes) : array
|
|
{
|
|
$namespacedUseImportTypes = [];
|
|
foreach ($useImportTypes as $useImportType) {
|
|
if (\strpos($useImportType->getClassName(), '\\') === \false) {
|
|
continue;
|
|
}
|
|
$namespacedUseImportTypes[] = $useImportType;
|
|
}
|
|
return $namespacedUseImportTypes;
|
|
}
|
|
}
|