Skip to content

Commit

Permalink
Updated Rector to commit c20f5ede4af5310a23ca8baffd2b5f74ae77d622
Browse files Browse the repository at this point in the history
carlos-granados/rector-src@c20f5ed Build rector for this repository (rectorphp#6)
  • Loading branch information
carlos-granados committed Oct 4, 2024
1 parent 7b857f1 commit adc64b4
Show file tree
Hide file tree
Showing 24 changed files with 425 additions and 88 deletions.
2 changes: 1 addition & 1 deletion config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
$rectorConfig->bootstrapFiles([]);
$rectorConfig->parallel();
// to avoid autoimporting out of the box
$rectorConfig->importNames(\false, \false);
$rectorConfig->importNames(\false, \false, \false);
$rectorConfig->removeUnusedImports(\false);
$rectorConfig->importShortClasses();
$rectorConfig->indent(' ', 4);
Expand Down
162 changes: 122 additions & 40 deletions rules/CodingStyle/Application/UseImportsAdder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Rector\CodingStyle\Application;

use RectorPrefix202410\Nette\Utils\Strings;
use PhpParser\Comment;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Declare_;
Expand All @@ -13,6 +14,8 @@
use PhpParser\Node\Stmt\Use_;
use PHPStan\Type\ObjectType;
use Rector\CodingStyle\ClassNameImport\UsedImportsResolver;
use Rector\Configuration\Option;
use Rector\Configuration\Parameter\SimpleParameterProvider;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
Expand All @@ -38,20 +41,20 @@ public function __construct(UsedImportsResolver $usedImportsResolver, TypeFactor
/**
* @param Stmt[] $stmts
* @param array<FullyQualifiedObjectType|AliasedObjectType> $useImportTypes
* @param array<FullyQualifiedObjectType|AliasedObjectType> $constantUseImportTypes
* @param array<FullyQualifiedObjectType|AliasedObjectType> $functionUseImportTypes
* @param array<FullyQualifiedObjectType|AliasedObjectType> $constantUseImportTypes
* @return Stmt[]
*/
public function addImportsToStmts(FileWithoutNamespace $fileWithoutNamespace, array $stmts, array $useImportTypes, array $constantUseImportTypes, array $functionUseImportTypes) : array
public function addImportsToStmts(FileWithoutNamespace $fileWithoutNamespace, array $stmts, array $useImportTypes, array $functionUseImportTypes, array $constantUseImportTypes) : array
{
$usedImports = $this->usedImportsResolver->resolveForStmts($stmts);
$existingUseImportTypes = $usedImports->getUseImports();
$existingConstantUseImports = $usedImports->getConstantImports();
$existingFunctionUseImports = $usedImports->getFunctionImports();
$useImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes);
$constantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImports);
$functionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImports);
$newUses = $this->createUses($useImportTypes, $constantUseImportTypes, $functionUseImportTypes, null);
$existingFunctionUseImportTypes = $usedImports->getFunctionImports();
$existingConstantUseImportTypes = $usedImports->getConstantImports();
$newUseImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes);
$newFunctionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImportTypes);
$newConstantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImportTypes);
$newUses = $this->createUses($newUseImportTypes, $newFunctionUseImportTypes, $newConstantUseImportTypes, null);
if ($newUses === []) {
return [$fileWithoutNamespace];
}
Expand All @@ -65,75 +68,92 @@ public function addImportsToStmts(FileWithoutNamespace $fileWithoutNamespace, ar
if (!$stmt instanceof Declare_) {
break;
}
$nodesToAdd = \array_merge([new Nop()], $newUses);
$this->mirrorUseComments($stmts, $newUses, $key + 1);
$position = $key + 1;
$useComments = $this->getAndRemoveExistingUseComments($stmts, $position);
// remove space before next use tweak
if (isset($stmts[$key + 1]) && ($stmts[$key + 1] instanceof Use_ || $stmts[$key + 1] instanceof GroupUse)) {
$stmts[$key + 1]->setAttribute(AttributeKey::ORIGINAL_NODE, null);
if (isset($stmts[$position]) && ($stmts[$position] instanceof Use_ || $stmts[$position] instanceof GroupUse)) {
$stmts[$position]->setAttribute(AttributeKey::ORIGINAL_NODE, null);
}
\array_splice($stmts, $position, 0, [new Nop()]);
++$position;
$fileWithoutNamespace->stmts = $this->insertUseNodesInStatements($stmts, $newUses, $position, \false);
if ($useComments !== []) {
$this->reapplyUseComments($useComments, $fileWithoutNamespace->stmts, $position);
}
\array_splice($stmts, $key + 1, 0, $nodesToAdd);
$fileWithoutNamespace->stmts = $stmts;
$fileWithoutNamespace->stmts = \array_values($fileWithoutNamespace->stmts);
return [$fileWithoutNamespace];
}
$this->mirrorUseComments($stmts, $newUses);
// make use stmts first
$fileWithoutNamespace->stmts = \array_merge($newUses, $this->resolveInsertNop($fileWithoutNamespace), $stmts);
$fileWithoutNamespace->stmts = \array_values($fileWithoutNamespace->stmts);
$useComments = $this->getAndRemoveExistingUseComments($stmts);
$fileWithoutNamespace->stmts = $this->insertUseNodesInStatements($fileWithoutNamespace->stmts, $newUses);
if ($useComments !== []) {
$this->reapplyUseComments($useComments, $fileWithoutNamespace->stmts);
}
return [$fileWithoutNamespace];
}
/**
* @param FullyQualifiedObjectType[] $useImportTypes
* @param FullyQualifiedObjectType[] $constantUseImportTypes
* @param FullyQualifiedObjectType[] $functionUseImportTypes
* @param FullyQualifiedObjectType[] $constantUseImportTypes
*/
public function addImportsToNamespace(Namespace_ $namespace, array $useImportTypes, array $constantUseImportTypes, array $functionUseImportTypes) : void
public function addImportsToNamespace(Namespace_ $namespace, array $useImportTypes, array $functionUseImportTypes, array $constantUseImportTypes) : void
{
$namespaceName = $this->getNamespaceName($namespace);
$existingUsedImports = $this->usedImportsResolver->resolveForStmts($namespace->stmts);
$existingUseImportTypes = $existingUsedImports->getUseImports();
$existingConstantUseImportTypes = $existingUsedImports->getConstantImports();
$existingFunctionUseImportTypes = $existingUsedImports->getFunctionImports();
$existingUseImportTypes = $this->typeFactory->uniquateTypes($existingUseImportTypes);
$useImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes);
$constantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImportTypes);
$functionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImportTypes);
$newUses = $this->createUses($useImportTypes, $constantUseImportTypes, $functionUseImportTypes, $namespaceName);
$newUseImportTypes = $this->diffFullyQualifiedObjectTypes($useImportTypes, $existingUseImportTypes);
$newFunctionUseImportTypes = $this->diffFullyQualifiedObjectTypes($functionUseImportTypes, $existingFunctionUseImportTypes);
$newConstantUseImportTypes = $this->diffFullyQualifiedObjectTypes($constantUseImportTypes, $existingConstantUseImportTypes);
$newUses = $this->createUses($newUseImportTypes, $newFunctionUseImportTypes, $newConstantUseImportTypes, $namespaceName);
if ($newUses === []) {
return;
}
$this->mirrorUseComments($namespace->stmts, $newUses);
$namespace->stmts = \array_merge($newUses, $this->resolveInsertNop($namespace), $namespace->stmts);
$namespace->stmts = \array_values($namespace->stmts);
$useComments = $this->getAndRemoveExistingUseComments($namespace->stmts);
$namespace->stmts = $this->insertUseNodesInStatements($namespace->stmts, $newUses);
if ($useComments !== []) {
$this->reapplyUseComments($useComments, $namespace->stmts);
}
}
/**
* @param Stmt[] $stmts
* @return Nop[]
* @param \Rector\PhpParser\Node\CustomNode\FileWithoutNamespace|\PhpParser\Node\Stmt\Namespace_ $namespace
*/
private function resolveInsertNop($namespace) : array
private function resolveInsertNop(array $stmts, int $position) : array
{
$currentStmt = $namespace->stmts[0] ?? null;
$currentStmt = $stmts[$position] ?? null;
if (!$currentStmt instanceof Stmt || $currentStmt instanceof Use_ || $currentStmt instanceof GroupUse) {
return [];
}
return [new Nop()];
}
/**
* @param Stmt[] $stmts
* @param Use_[] $newUses
* @return Comment[]
*/
private function mirrorUseComments(array $stmts, array $newUses, int $indexStmt = 0) : void
private function getAndRemoveExistingUseComments(array $stmts, int $indexStmt = 0) : array
{
$comments = [];
if ($stmts === []) {
return;
return $comments;
}
if (isset($stmts[$indexStmt]) && $stmts[$indexStmt] instanceof Use_) {
$comments = (array) $stmts[$indexStmt]->getAttribute(AttributeKey::COMMENTS);
if ($comments !== []) {
$newUses[0]->setAttribute(AttributeKey::COMMENTS, $stmts[$indexStmt]->getAttribute(AttributeKey::COMMENTS));
$stmts[$indexStmt]->setAttribute(AttributeKey::COMMENTS, []);
}
}
return $comments;
}
/**
* @param Comment[] $comments
* @param Stmt[] $stmts
*/
private function reapplyUseComments(array $comments, array $stmts, int $indexStmt = 0) : void
{
if (isset($stmts[$indexStmt])) {
$stmts[$indexStmt]->setAttribute(AttributeKey::COMMENTS, $comments);
}
}
/**
* @param array<FullyQualifiedObjectType|AliasedObjectType> $mainTypes
Expand All @@ -153,24 +173,33 @@ private function diffFullyQualifiedObjectTypes(array $mainTypes, array $typesToR
}
/**
* @param array<AliasedObjectType|FullyQualifiedObjectType> $useImportTypes
* @param array<FullyQualifiedObjectType|AliasedObjectType> $constantUseImportTypes
* @param array<FullyQualifiedObjectType|AliasedObjectType> $functionUseImportTypes
* @param array<FullyQualifiedObjectType|AliasedObjectType> $constantUseImportTypes
* @return Use_[]
*/
private function createUses(array $useImportTypes, array $constantUseImportTypes, array $functionUseImportTypes, ?string $namespaceName) : array
private function createUses(array $useImportTypes, array $functionUseImportTypes, array $constantUseImportTypes, ?string $namespaceName) : array
{
$newUses = [];
/** @var array<Use_::TYPE_*, array<AliasedObjectType|FullyQualifiedObjectType>> $importsMapping */
$importsMapping = [Use_::TYPE_NORMAL => $useImportTypes, Use_::TYPE_CONSTANT => $constantUseImportTypes, Use_::TYPE_FUNCTION => $functionUseImportTypes];
$importsMapping = [Use_::TYPE_NORMAL => $useImportTypes, Use_::TYPE_FUNCTION => $functionUseImportTypes, Use_::TYPE_CONSTANT => $constantUseImportTypes];
foreach ($importsMapping as $type => $importTypes) {
/** @var AliasedObjectType|FullyQualifiedObjectType $importType */
$newUsesPerType = [];
foreach ($importTypes as $importType) {
if ($namespaceName !== null && $this->isCurrentNamespace($namespaceName, $importType)) {
continue;
}
// already imported in previous cycle
$newUses[] = $importType->getUseNode($type);
$newUsesPerType[] = $importType->getUseNode($type);
}
if (SimpleParameterProvider::provideBoolParameter(Option::IMPORT_INSERT_SORTED)) {
//sort uses by name in ascending order
\usort($newUsesPerType, function (Use_ $use1, Use_ $use2) : int {
$name1 = $use1->uses[0]->name->toString();
$name2 = $use2->uses[0]->name->toString();
return \strcmp($name1, $name2);
});
}
$newUses = \array_merge($newUses, $newUsesPerType);
}
return $newUses;
}
Expand All @@ -189,4 +218,57 @@ private function isCurrentNamespace(string $namespaceName, ObjectType $objectTyp
}
return \strpos($afterCurrentNamespace, '\\') === \false;
}
/**
* @param Stmt[] $stmts
* @param Use_[] $newUses
* @return Stmt[]
*/
private function insertUseNodesInStatements(array $stmts, array $newUses, int $position = 0, bool $addSpace = \true) : array
{
$importInsertSorted = SimpleParameterProvider::provideBoolParameter(Option::IMPORT_INSERT_SORTED);
if ($importInsertSorted && isset($stmts[$position]) && ($stmts[$position] instanceof Use_ || $stmts[$position] instanceof GroupUse)) {
foreach ($newUses as $newUse) {
do {
$useListPosition = 0;
$prefix = '';
if (!isset($stmts[$position]) || !$stmts[$position] instanceof Use_ && !$stmts[$position] instanceof GroupUse) {
break;
}
if ($stmts[$position] instanceof GroupUse) {
$prefix = $stmts[$position]->prefix->toString() . '\\';
}
$parentUseType = $stmts[$position]->type;
$newUseType = $newUse->type;
foreach ($stmts[$position]->uses as $use) {
$currentUseType = $parentUseType === Use_::TYPE_UNKNOWN ? $use->type : $parentUseType;
if ($newUseType < $currentUseType) {
break 2;
}
if ($newUseType === $currentUseType && $prefix . $use->name->toString() > $newUse->uses[0]->name->toString()) {
break 2;
}
++$useListPosition;
}
++$position;
} while (\true);
if ($useListPosition === 0) {
\array_splice($stmts, $position, 0, [$newUse]);
++$position;
} else {
\assert($stmts[$position] instanceof Use_ || $stmts[$position] instanceof GroupUse);
if ($prefix !== '') {
$newUse->uses[0]->name = new Name(\substr($newUse->uses[0]->name->toString(), \strlen($prefix)));
$newUse->uses[0]->type = $newUse->type;
}
\array_splice($stmts[$position]->uses, $useListPosition, 0, [$newUse->uses[0]]);
}
}
} else {
if ($addSpace) {
$newUses = \array_merge($newUses, $this->resolveInsertNop($stmts, $position));
}
\array_splice($stmts, $position, 0, $newUses);
}
return \array_values($stmts);
}
}
Loading

0 comments on commit adc64b4

Please sign in to comment.