Updated Rector to commit 8c20a7ed0a2eb3d26a275c0fef16b8f413e02b42

8c20a7ed0a [NodeTypeResolver] Clean up UseImportsResolver check on ClassRenamePhpDocNodeVisitor (#6500)
This commit is contained in:
Tomas Votruba 2024-11-24 13:40:52 +00:00
parent 57ac216872
commit d68ed070fe
5 changed files with 28 additions and 65 deletions

View File

@ -50,7 +50,7 @@ final class ObjectTypeSpecifier
/**
* @return \PHPStan\Type\TypeWithClassName|\Rector\StaticTypeMapper\ValueObject\Type\NonExistingObjectType|\PHPStan\Type\UnionType|\PHPStan\Type\MixedType|\PHPStan\Type\Generic\TemplateType
*/
public function narrowToFullyQualifiedOrAliasedObjectType(Node $node, ObjectType $objectType, ?\PHPStan\Analyser\Scope $scope)
public function narrowToFullyQualifiedOrAliasedObjectType(Node $node, ObjectType $objectType, ?\PHPStan\Analyser\Scope $scope, bool $withPreslash = \false)
{
$uses = $this->useImportsResolver->resolve();
$aliasedObjectType = $this->matchAliasedObjectType($objectType, $uses);
@ -69,6 +69,7 @@ final class ObjectTypeSpecifier
return new FullyQualifiedObjectType($className);
}
// probably in same namespace
$namespaceName = null;
if ($scope instanceof Scope) {
$namespaceName = $scope->getNamespace();
if ($namespaceName !== null) {
@ -77,8 +78,6 @@ final class ObjectTypeSpecifier
return new FullyQualifiedObjectType($newClassName);
}
}
}
if ($scope instanceof Scope) {
$classReflection = $scope->getClassReflection();
if ($classReflection instanceof ClassReflection) {
$templateTags = $classReflection->getTemplateTags();
@ -86,18 +85,31 @@ final class ObjectTypeSpecifier
$templateTypeScope = $nameScope->getTemplateTypeScope();
if (!$templateTypeScope instanceof TemplateTypeScope) {
// invalid type
return new NonExistingObjectType($className);
return $this->resolveNamespacedNonExistingObjectType($namespaceName, $className, $withPreslash);
}
$currentTemplateTag = $templateTags[$className] ?? null;
if ($currentTemplateTag === null) {
// invalid type
return new NonExistingObjectType($className);
return $this->resolveNamespacedNonExistingObjectType($namespaceName, $className, $withPreslash);
}
return TemplateTypeFactory::create($templateTypeScope, $currentTemplateTag->getName(), $currentTemplateTag->getBound(), $currentTemplateTag->getVariance());
}
}
// invalid type
return new NonExistingObjectType($className);
return $this->resolveNamespacedNonExistingObjectType($namespaceName, $className, $withPreslash);
}
private function resolveNamespacedNonExistingObjectType(?string $namespacedName, string $className, bool $withPreslash) : NonExistingObjectType
{
if ($namespacedName === null) {
return new NonExistingObjectType($className);
}
if ($withPreslash) {
return new NonExistingObjectType($className);
}
if (\strpos($className, '\\') !== \false) {
return new NonExistingObjectType($className);
}
return new NonExistingObjectType($namespacedName . '\\' . $className);
}
/**
* @param array<Use_|GroupUse> $uses

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = 'ed6887072d32d36be5f9dbe8d911316f552da3c5';
public const PACKAGE_VERSION = '8c20a7ed0a2eb3d26a275c0fef16b8f413e02b42';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2024-11-24 20:03:45';
public const RELEASE_DATE = '2024-11-24 20:38:26';
/**
* @var int
*/

View File

@ -172,7 +172,7 @@ final class NodeTypeResolver
$type = $this->genericClassStringTypeCorrector->correct($type);
if ($type instanceof ObjectType) {
$scope = $node->getAttribute(AttributeKey::SCOPE);
$type = $this->objectTypeSpecifier->narrowToFullyQualifiedOrAliasedObjectType($node, $type, $scope);
$type = $this->objectTypeSpecifier->narrowToFullyQualifiedOrAliasedObjectType($node, $type, $scope, \true);
}
return $type;
}

View File

@ -4,19 +4,14 @@ declare (strict_types=1);
namespace Rector\NodeTypeResolver\PhpDocNodeVisitor;
use PhpParser\Node as PhpNode;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Use_;
use PHPStan\Analyser\Scope;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Generic\TemplateObjectType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\Exception\ShouldNotHappenException;
use Rector\Naming\Naming\UseImportsResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\ValueObject\OldToNewType;
use Rector\PhpDocParser\PhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor;
use Rector\Renaming\Collector\RenamedNameCollector;
@ -29,10 +24,6 @@ final class ClassRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
* @readonly
*/
private StaticTypeMapper $staticTypeMapper;
/**
* @readonly
*/
private UseImportsResolver $useImportsResolver;
/**
* @readonly
*/
@ -43,10 +34,9 @@ final class ClassRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
private array $oldToNewTypes = [];
private bool $hasChanged = \false;
private ?PhpNode $currentPhpNode = null;
public function __construct(StaticTypeMapper $staticTypeMapper, UseImportsResolver $useImportsResolver, RenamedNameCollector $renamedNameCollector)
public function __construct(StaticTypeMapper $staticTypeMapper, RenamedNameCollector $renamedNameCollector)
{
$this->staticTypeMapper = $staticTypeMapper;
$this->useImportsResolver = $useImportsResolver;
$this->renamedNameCollector = $renamedNameCollector;
}
public function setCurrentPhpNode(PhpNode $phpNode) : void
@ -114,51 +104,10 @@ final class ClassRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
return $name;
}
$staticType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($identifierTypeNode, $phpNode);
if (!$staticType instanceof ObjectType) {
return $name;
}
if ($staticType instanceof ShortenedObjectType || $staticType instanceof AliasedObjectType) {
return $name;
}
$uses = $this->useImportsResolver->resolve();
$originalNode = $phpNode->getAttribute(AttributeKey::ORIGINAL_NODE);
$scope = $originalNode instanceof PhpNode ? $originalNode->getAttribute(AttributeKey::SCOPE) : $phpNode->getAttribute(AttributeKey::SCOPE);
if (!$scope instanceof Scope) {
if (!$originalNode instanceof PhpNode) {
return $this->resolveNamefromUse($uses, $name);
}
// @template is to not be renamed
if ($staticType instanceof TemplateObjectType) {
return '';
}
$namespaceName = $scope->getNamespace();
if ($namespaceName === null) {
return $this->resolveNamefromUse($uses, $name);
}
if ($uses === []) {
return $namespaceName . '\\' . $name;
}
$nameFromUse = $this->resolveNamefromUse($uses, $name);
if ($nameFromUse !== $name) {
return $nameFromUse;
}
return $namespaceName . '\\' . $nameFromUse;
}
/**
* @param array<Use_|GroupUse> $uses
*/
private function resolveNamefromUse(array $uses, string $name) : string
{
foreach ($uses as $use) {
$prefix = $this->useImportsResolver->resolvePrefix($use);
foreach ($use->uses as $useUse) {
if ($useUse->alias instanceof Identifier) {
continue;
}
$lastName = $useUse->name->getLast();
if ($lastName === $name) {
return $prefix . $useUse->name->toString();
}
}
}
return $name;
}
/**

View File

@ -90,9 +90,11 @@ final class IdentifierPhpDocTypeMapper implements PhpDocTypeMapperInterface
if ($loweredName === 'iterable') {
return new IterableType(new MixedType(), new MixedType());
}
$withPreslash = \false;
if (\strncmp($identifierTypeNode->name, '\\', \strlen('\\')) === 0) {
$typeWithoutPreslash = Strings::substring($identifierTypeNode->name, 1);
$objectType = new FullyQualifiedObjectType($typeWithoutPreslash);
$withPreslash = \true;
} else {
if ($identifierTypeNode->name === 'scalar') {
// pseudo type, see https://www.php.net/manual/en/language.types.intro.php
@ -103,7 +105,7 @@ final class IdentifierPhpDocTypeMapper implements PhpDocTypeMapperInterface
$objectType = new ObjectType($identifierTypeNode->name);
}
$scope = $node->getAttribute(AttributeKey::SCOPE);
return $this->objectTypeSpecifier->narrowToFullyQualifiedOrAliasedObjectType($node, $objectType, $scope);
return $this->objectTypeSpecifier->narrowToFullyQualifiedOrAliasedObjectType($node, $objectType, $scope, $withPreslash);
}
/**
* @return \PHPStan\Type\MixedType|\Rector\StaticTypeMapper\ValueObject\Type\SelfObjectType