mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-07 03:40:50 +00:00
[Experiment][Naming] Keep GroupUse Stmt on UseImportsResolver::resolveForNode() (#2349)
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
f8c204adba
commit
3fe07aa6a1
|
@ -6,6 +6,7 @@ namespace Rector\BetterPhpDocParser\PhpDocParser;
|
|||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
|
@ -48,7 +49,7 @@ final class ClassAnnotationMatcher
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
* @param Use_[]|GroupUse[] $uses
|
||||
*/
|
||||
private function resolveFullyQualifiedClass(array $uses, Node $node, string $tag): string
|
||||
{
|
||||
|
@ -72,29 +73,25 @@ final class ClassAnnotationMatcher
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
* @param Use_[]|GroupUse[] $uses
|
||||
*/
|
||||
private function resolveAsAliased(array $uses, string $tag): string
|
||||
{
|
||||
foreach ($uses as $use) {
|
||||
$prefix = $use instanceof GroupUse
|
||||
? $use->prefix . '\\'
|
||||
: '';
|
||||
$useUses = $use->uses;
|
||||
// skip group uses or empty
|
||||
if (count($useUses) !== 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// uses already removed
|
||||
if (! isset($useUses[0])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($useUses as $useUse) {
|
||||
if (! $useUse->alias instanceof Identifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $useUses[0]->alias instanceof Identifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$alias = $useUses[0]->alias;
|
||||
if ($alias->toString() === $tag) {
|
||||
return $useUses[0]->name->toString();
|
||||
$alias = $useUse->alias;
|
||||
if ($alias->toString() === $tag) {
|
||||
return $prefix . $useUse->name->toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Rector\PostRector\Collector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use Rector\Core\Provider\CurrentFileProvider;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\Naming\Naming\UseImportsResolver;
|
||||
|
@ -63,11 +64,14 @@ final class UseNodesToAddCollector implements NodeCollectorInterface
|
|||
$uses = $this->useImportsResolver->resolveForNode($node);
|
||||
|
||||
foreach ($uses as $use) {
|
||||
$prefix = $use instanceof GroupUse
|
||||
? $use->prefix . '\\'
|
||||
: '';
|
||||
foreach ($use->uses as $useUse) {
|
||||
if ($useUse->alias !== null) {
|
||||
$objectTypes[] = new AliasedObjectType($useUse->alias->toString(), (string) $useUse->name);
|
||||
$objectTypes[] = new AliasedObjectType($useUse->alias->toString(), $prefix . $useUse->name);
|
||||
} else {
|
||||
$objectTypes[] = new FullyQualifiedObjectType((string) $useUse->name);
|
||||
$objectTypes[] = new FullyQualifiedObjectType($prefix . $useUse->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Rector\StaticTypeMapper\Naming;
|
|||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use PHPStan\Analyser\NameScope;
|
||||
|
@ -81,7 +82,7 @@ final class NameScopeFactory
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $useNodes
|
||||
* @param Use_[]|GroupUse[] $useNodes
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private function resolveUseNamesByAlias(array $useNodes): array
|
||||
|
@ -89,6 +90,9 @@ final class NameScopeFactory
|
|||
$useNamesByAlias = [];
|
||||
|
||||
foreach ($useNodes as $useNode) {
|
||||
$prefix = $useNode instanceof GroupUse
|
||||
? $useNode->prefix . '\\'
|
||||
: '';
|
||||
foreach ($useNode->uses as $useUse) {
|
||||
/** @var UseUse $useUse */
|
||||
$aliasName = $useUse->getAlias()
|
||||
|
@ -97,7 +101,7 @@ final class NameScopeFactory
|
|||
// uses must be lowercase, as PHPStan lowercases it
|
||||
$lowercasedAliasName = strtolower($aliasName);
|
||||
|
||||
$useNamesByAlias[$lowercasedAliasName] = $useUse->name->toString();
|
||||
$useNamesByAlias[$lowercasedAliasName] = $prefix . $useUse->name->toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Rector\Tests\Naming\Naming\UseImportsResolver;
|
|||
|
||||
use Iterator;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Naming\Naming\UseImportsResolver;
|
||||
use Rector\Testing\PHPUnit\AbstractTestCase;
|
||||
|
@ -45,7 +46,9 @@ final class UseImportsResolverTest extends AbstractTestCase
|
|||
|
||||
foreach ($resolvedUses as $resolvedUse) {
|
||||
foreach ($resolvedUse->uses as $useUse) {
|
||||
$stringUses[] = $useUse->name->tostring();
|
||||
$stringUses[] = $resolvedUse instanceof Use_
|
||||
? $useUse->name->tostring()
|
||||
: $resolvedUse->prefix->toString() . '\\' . $useUse->name->toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Rector\CodingStyle\NodeAnalyzer;
|
|||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
|
@ -37,35 +38,38 @@ final class UseImportNameMatcher
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
* @param Use_[]|GroupUse[] $uses
|
||||
*/
|
||||
public function matchNameWithUses(string $tag, array $uses): ?string
|
||||
{
|
||||
foreach ($uses as $use) {
|
||||
$prefix = $use instanceof GroupUse
|
||||
? $use->prefix . '\\'
|
||||
: '';
|
||||
foreach ($use->uses as $useUse) {
|
||||
if (! $this->isUseMatchingName($tag, $useUse)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->resolveName($tag, $useUse);
|
||||
return $this->resolveName($prefix, $tag, $useUse);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function resolveName(string $tag, UseUse $useUse): string
|
||||
public function resolveName(string $prefix, string $tag, UseUse $useUse): string
|
||||
{
|
||||
if ($useUse->alias === null) {
|
||||
return $useUse->name->toString();
|
||||
return $prefix . $useUse->name->toString();
|
||||
}
|
||||
|
||||
$unaliasedShortClass = Strings::substring($tag, Strings::length($useUse->alias->toString()));
|
||||
if (\str_starts_with($unaliasedShortClass, '\\')) {
|
||||
return $useUse->name . $unaliasedShortClass;
|
||||
return $prefix . $useUse->name . $unaliasedShortClass;
|
||||
}
|
||||
|
||||
return $useUse->name . '\\' . $unaliasedShortClass;
|
||||
return $prefix . $useUse->name . '\\' . $unaliasedShortClass;
|
||||
}
|
||||
|
||||
private function isUseMatchingName(string $tag, UseUse $useUse): bool
|
||||
|
|
|
@ -9,6 +9,7 @@ use PhpParser\Node\Expr\ConstFetch;
|
|||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\UseImportsResolver;
|
||||
|
@ -101,7 +102,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $useNodes
|
||||
* @param Use_[]|GroupUse[] $useNodes
|
||||
*/
|
||||
private function getFullyQualifiedName(array $useNodes, ConstFetch|FuncCall $node): ?string
|
||||
{
|
||||
|
@ -113,22 +114,31 @@ CODE_SAMPLE
|
|||
$typeFilter = $node instanceof ConstFetch ? Use_::TYPE_CONSTANT : Use_::TYPE_FUNCTION;
|
||||
|
||||
foreach ($useNodes as $useNode) {
|
||||
$prefix = $this->resolvePrefix($useNode);
|
||||
|
||||
if ($useNode->type !== $typeFilter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($useNode->uses as $useUse) {
|
||||
if ($name === $useUse->name->toLowerString()) {
|
||||
return $useUse->name->toString();
|
||||
if ($name === $prefix . $useUse->name->toLowerString()) {
|
||||
return $prefix . $useUse->name->toString();
|
||||
}
|
||||
|
||||
$alias = $useUse->getAlias();
|
||||
if ($name === $alias->toLowerString()) {
|
||||
return $useUse->name->toString();
|
||||
return $prefix . $useUse->name->toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function resolvePrefix(Use_|GroupUse $useNode): string
|
||||
{
|
||||
return $useNode instanceof GroupUse
|
||||
? $useNode->prefix . '\\'
|
||||
: '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@ namespace Rector\Naming\Naming;
|
|||
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
|
||||
final class AliasNameResolver
|
||||
{
|
||||
public function __construct(
|
||||
private readonly NodeNameResolver $nodeNameResolver,
|
||||
private readonly UseImportsResolver $useImportsResolver,
|
||||
) {
|
||||
}
|
||||
|
@ -22,25 +21,22 @@ final class AliasNameResolver
|
|||
$nameString = $name->toString();
|
||||
|
||||
foreach ($uses as $use) {
|
||||
$prefix = $use instanceof GroupUse
|
||||
? $use->prefix . '\\'
|
||||
: '';
|
||||
$useUses = $use->uses;
|
||||
if (count($useUses) > 1) {
|
||||
continue;
|
||||
}
|
||||
foreach ($useUses as $useUse) {
|
||||
if (! $useUse->alias instanceof Identifier) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! isset($useUses[0])) {
|
||||
continue;
|
||||
}
|
||||
$name = $prefix . $useUse->name->toString();
|
||||
if ($name !== $nameString) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$useUse = $useUses[0];
|
||||
if (! $useUse->alias instanceof Identifier) {
|
||||
continue;
|
||||
return (string) $useUse->getAlias();
|
||||
}
|
||||
|
||||
if (! $this->nodeNameResolver->isName($useUse->name, $nameString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return (string) $useUse->getAlias();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -5,11 +5,10 @@ declare(strict_types=1);
|
|||
namespace Rector\Naming\Naming;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
|
||||
|
@ -21,7 +20,7 @@ final class UseImportsResolver
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Use_[]
|
||||
* @return Use_[]|GroupUse[]
|
||||
*/
|
||||
public function resolveForNode(Node $node): array
|
||||
{
|
||||
|
@ -33,29 +32,9 @@ final class UseImportsResolver
|
|||
return [];
|
||||
}
|
||||
|
||||
$collectedUses = [];
|
||||
|
||||
foreach ($namespace->stmts as $stmt) {
|
||||
if ($stmt instanceof Use_) {
|
||||
$collectedUses[] = $stmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($stmt instanceof GroupUse) {
|
||||
$groupUseUses = [];
|
||||
foreach ($stmt->uses as $useUse) {
|
||||
$groupUseUses[] = new UseUse(
|
||||
new Name($stmt->prefix . '\\' . $useUse->name),
|
||||
$useUse->alias,
|
||||
$useUse->type,
|
||||
$useUse->getAttributes()
|
||||
);
|
||||
}
|
||||
|
||||
$collectedUses[] = new Use_($groupUseUses, $stmt->type, $stmt->getAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
return $collectedUses;
|
||||
return array_filter(
|
||||
$namespace->stmts,
|
||||
fn (Stmt $stmt): bool => $stmt instanceof Use_ || $stmt instanceof GroupUse
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use PhpParser\Node\Name;
|
|||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
|
@ -420,9 +421,14 @@ final class ClassRenamer
|
|||
}
|
||||
|
||||
foreach ($uses as $use) {
|
||||
if ($this->nodeNameResolver->isName($use, $newName)) {
|
||||
// name already exists
|
||||
return false;
|
||||
$prefix = $use instanceof GroupUse
|
||||
? $use->prefix . '\\'
|
||||
: '';
|
||||
foreach ($use->uses as $useUse) {
|
||||
if ($prefix . $useUse->name->toString() === $newName) {
|
||||
// name already exists
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use Nette\Utils\Strings;
|
|||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\GroupUse;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use PHPStan\Analyser\Scope;
|
||||
|
@ -90,7 +91,7 @@ final class ObjectTypeSpecifier
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
* @param Use_[]|GroupUse[] $uses
|
||||
*/
|
||||
private function matchAliasedObjectType(Node $node, ObjectType $objectType, array $uses): ?AliasedObjectType
|
||||
{
|
||||
|
@ -102,14 +103,17 @@ final class ObjectTypeSpecifier
|
|||
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
foreach ($uses as $use) {
|
||||
$prefix = $use instanceof GroupUse
|
||||
? $use->prefix . '\\'
|
||||
: '';
|
||||
foreach ($use->uses as $useUse) {
|
||||
if ($useUse->alias === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$useName = $useUse->name->toString();
|
||||
$useName = $prefix . $useUse->name->toString();
|
||||
$alias = $useUse->alias->toString();
|
||||
$fullyQualifiedName = $useUse->name->toString();
|
||||
$fullyQualifiedName = $prefix . $useUse->name->toString();
|
||||
|
||||
$processAliasedObject = $this->processAliasedObject(
|
||||
$alias,
|
||||
|
@ -154,7 +158,7 @@ final class ObjectTypeSpecifier
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
* @param Use_[]|GroupUse[] $uses
|
||||
*/
|
||||
private function matchShortenedObjectType(
|
||||
ObjectType $objectType,
|
||||
|
@ -165,17 +169,20 @@ final class ObjectTypeSpecifier
|
|||
}
|
||||
|
||||
foreach ($uses as $use) {
|
||||
$prefix = $use instanceof GroupUse
|
||||
? $use->prefix . '\\'
|
||||
: '';
|
||||
foreach ($use->uses as $useUse) {
|
||||
if ($useUse->alias !== null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$partialNamespaceObjectType = $this->matchPartialNamespaceObjectType($objectType, $useUse);
|
||||
$partialNamespaceObjectType = $this->matchPartialNamespaceObjectType($prefix, $objectType, $useUse);
|
||||
if ($partialNamespaceObjectType !== null) {
|
||||
return $partialNamespaceObjectType;
|
||||
}
|
||||
|
||||
$partialNamespaceObjectType = $this->matchClassWithLastUseImportPart($objectType, $useUse);
|
||||
$partialNamespaceObjectType = $this->matchClassWithLastUseImportPart($prefix, $objectType, $useUse);
|
||||
if ($partialNamespaceObjectType instanceof FullyQualifiedObjectType) {
|
||||
// keep Generic items
|
||||
if ($objectType instanceof GenericObjectType) {
|
||||
|
@ -198,8 +205,11 @@ final class ObjectTypeSpecifier
|
|||
return null;
|
||||
}
|
||||
|
||||
private function matchPartialNamespaceObjectType(ObjectType $objectType, UseUse $useUse): ?ShortenedObjectType
|
||||
{
|
||||
private function matchPartialNamespaceObjectType(
|
||||
string $prefix,
|
||||
ObjectType $objectType,
|
||||
UseUse $useUse
|
||||
): ?ShortenedObjectType {
|
||||
// partial namespace
|
||||
if (! \str_starts_with($objectType->getClassName(), $useUse->name->getLast() . '\\')) {
|
||||
return null;
|
||||
|
@ -207,7 +217,7 @@ final class ObjectTypeSpecifier
|
|||
|
||||
$classNameWithoutLastUsePart = Strings::after($objectType->getClassName(), '\\', 1);
|
||||
|
||||
$connectedClassName = $useUse->name->toString() . '\\' . $classNameWithoutLastUsePart;
|
||||
$connectedClassName = $prefix . $useUse->name->toString() . '\\' . $classNameWithoutLastUsePart;
|
||||
if (! $this->reflectionProvider->hasClass($connectedClassName)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -222,20 +232,23 @@ final class ObjectTypeSpecifier
|
|||
/**
|
||||
* @return FullyQualifiedObjectType|ShortenedObjectType|null
|
||||
*/
|
||||
private function matchClassWithLastUseImportPart(ObjectType $objectType, UseUse $useUse): ?ObjectType
|
||||
{
|
||||
private function matchClassWithLastUseImportPart(
|
||||
string $prefix,
|
||||
ObjectType $objectType,
|
||||
UseUse $useUse
|
||||
): ?ObjectType {
|
||||
if ($useUse->name->getLast() !== $objectType->getClassName()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->reflectionProvider->hasClass($useUse->name->toString())) {
|
||||
if (! $this->reflectionProvider->hasClass($prefix . $useUse->name->toString())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($objectType->getClassName() === $useUse->name->toString()) {
|
||||
if ($objectType->getClassName() === $prefix . $useUse->name->toString()) {
|
||||
return new FullyQualifiedObjectType($objectType->getClassName());
|
||||
}
|
||||
|
||||
return new ShortenedObjectType($objectType->getClassName(), $useUse->name->toString());
|
||||
return new ShortenedObjectType($objectType->getClassName(), $prefix . $useUse->name->toString());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user