Fix doc importing on Doctrine annotation class rename (#264)

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Tomas Votruba 2021-06-22 12:30:29 +02:00 committed by GitHub
parent a8ccfeb3d5
commit a41384bc00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 279 additions and 88 deletions

View File

@ -92,8 +92,8 @@ if (! $entityTagValueNode instanceof DoctrineAnnotationTagValueNode) {
return null;
}
$annotationClass = $entityTagValueNode->getAnnotationClass();
var_dump($annotationClass); // "Doctrine\ORM\Mapping\Entity"
$annotationClass = $entityTagValueNode->identifierTypeNode;
var_dump($annotationClass); // \PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode("Doctrine\ORM\Mapping\Entity")
$values = $entityTagValueNode->getValues();
var_dump($values); // []

View File

@ -28,7 +28,7 @@
"rector/rector-nette": "^0.11.4",
"rector/rector-nette-to-symfony": "^0.11.3",
"rector/rector-phpunit": "^0.11.1",
"rector/rector-symfony": "^0.11.5",
"rector/rector-symfony": "^0.11.6",
"sebastian/diff": "^4.0.4",
"ssch/typo3-rector": "^0.11.14",
"symfony/console": "^5.3",
@ -55,7 +55,7 @@
"phpstan/phpstan-nette": "^0.12.19",
"phpunit/phpunit": "^9.5",
"rector/rector-generator": "^0.1.7",
"rector/phpstan-rules": "^0.3",
"rector/phpstan-rules": "^0.3.3",
"symplify/coding-standard": "^9.3.22",
"symplify/easy-ci": "^9.3.22",
"symplify/easy-coding-standard": "^9.3.22",

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDoc;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDoc\DoctrineAnnotation\AbstractValuesAwareNode;
use Stringable;
@ -13,7 +14,7 @@ final class DoctrineAnnotationTagValueNode extends AbstractValuesAwareNode imple
* @param array<mixed, mixed> $values
*/
public function __construct(
private string $annotationClass,
public IdentifierTypeNode $identifierTypeNode,
?string $originalContent = null,
array $values = [],
?string $silentKey = null
@ -46,8 +47,8 @@ final class DoctrineAnnotationTagValueNode extends AbstractValuesAwareNode imple
return sprintf('(%s)', $itemContents);
}
public function getAnnotationClass(): string
public function hasClassName(string $className): bool
{
return $this->annotationClass;
return $this->identifierTypeNode->name === $className;
}
}

View File

@ -258,13 +258,13 @@ final class PhpDocInfo
$doctrineAnnotationTagValueNode = $phpDocChildNode->value;
$annotationClass = $doctrineAnnotationTagValueNode->getAnnotationClass();
if ($annotationClass === $desiredClass) {
if ($doctrineAnnotationTagValueNode->hasClassName($desiredClass)) {
return $doctrineAnnotationTagValueNode;
}
// fnmatch
if ($this->isFnmatch($annotationClass, $desiredClass)) {
$identifierTypeNode = $doctrineAnnotationTagValueNode->identifierTypeNode;
if ($this->isFnmatch($identifierTypeNode->name, $desiredClass)) {
return $doctrineAnnotationTagValueNode;
}
}
@ -348,7 +348,7 @@ final class PhpDocInfo
{
if ($phpDocTagValueNode instanceof DoctrineAnnotationTagValueNode) {
$spacelessPhpDocTagNode = new SpacelessPhpDocTagNode(
'@\\' . $phpDocTagValueNode->getAnnotationClass(),
'@\\' . $phpDocTagValueNode->identifierTypeNode,
$phpDocTagValueNode
);
$this->addPhpDocTagNode($spacelessPhpDocTagNode);

View File

@ -122,11 +122,9 @@ final class PhpDocClassRenamer
Node $node,
array $oldToNewClasses
): void {
if ($doctrineAnnotationTagValueNode->getAnnotationClass() === 'Doctrine\ORM\Mapping\Embedded') {
$classKey = 'class';
} else {
$classKey = 'targetEntity';
}
$classKey = $doctrineAnnotationTagValueNode->hasClassName(
'Doctrine\ORM\Mapping\Embedded'
) ? 'class' : 'targetEntity';
$targetEntity = $doctrineAnnotationTagValueNode->getValueWithoutQuotes($classKey);
if ($targetEntity === null) {

View File

@ -26,8 +26,9 @@ final class PhpDocTagRemover
}
if ($phpDocChildNode->value instanceof DoctrineAnnotationTagValueNode) {
$tagClass = $phpDocChildNode->value->getAnnotationClass();
if ($tagClass === $name) {
$doctrineAnnotationTagValueNode = $phpDocChildNode->value;
if ($doctrineAnnotationTagValueNode->hasClassName($name)) {
unset($phpDocNode->children[$key]);
$phpDocInfo->markAsChanged();
}

View File

@ -8,6 +8,7 @@ use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use Rector\BetterPhpDocParser\Attributes\AttributeMirrorer;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
@ -155,7 +156,7 @@ final class DoctrineAnnotationDecorator
$formerStartEnd = $genericTagValueNode->getAttribute(PhpDocAttributeKey::START_AND_END);
$doctrineAnnotationTagValueNode = new DoctrineAnnotationTagValueNode(
$fullyQualifiedAnnotationClass,
new IdentifierTypeNode($fullyQualifiedAnnotationClass),
$genericTagValueNode->value,
$values,
SilentKeyMap::CLASS_NAMES_TO_SILENT_KEYS[$fullyQualifiedAnnotationClass] ?? null

View File

@ -8,6 +8,7 @@ use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFalseNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprTrueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher;
@ -109,6 +110,7 @@ final class PlainValueParser
$tokenIterator->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
$tokenIterator->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
return new DoctrineAnnotationTagValueNode($fullyQualifiedAnnotationClass, $annotationShortName, $values);
$identifierTypeNode = new IdentifierTypeNode($fullyQualifiedAnnotationClass);
return new DoctrineAnnotationTagValueNode($identifierTypeNode, $annotationShortName, $values);
}
}

View File

@ -153,6 +153,11 @@ abstract class AbstractValuesAwareNode implements PhpDocTagValueNode
return $explicitKeysValues;
}
public function markAsChanged(): void
{
$this->hasChanged = true;
}
/**
* @param mixed|string $value
* @return mixed|string

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Rector\BetterPhpDocParser\ValueObjectFactory\PhpDocNode\Symfony;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
final class SymfonyRouteTagValueNodeFactory
@ -14,7 +15,7 @@ final class SymfonyRouteTagValueNodeFactory
public function createFromItems(array $items): DoctrineAnnotationTagValueNode
{
return new DoctrineAnnotationTagValueNode(
'Symfony\Component\Routing\Annotation\Route',
new IdentifierTypeNode('Symfony\Component\Routing\Annotation\Route'),
null,
$items,
'path'

View File

@ -11,10 +11,10 @@ use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Namespace_;
use Rector\Autodiscovery\Configuration\CategoryNamespaceProvider;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\ValueObject\Application\File;
use Rector\FileSystemRector\ValueObject\AddedFileWithNodes;
use Rector\PSR4\Collector\RenamedClassesCollector;
use Rector\PSR4\FileInfoAnalyzer\FileInfoDeletionAnalyzer;
use Rector\PSR4\FileRelocationResolver;
use Symplify\SmartFileSystem\SmartFileInfo;
@ -25,7 +25,7 @@ final class AddedFileWithNodesFactory
private BetterNodeFinder $betterNodeFinder,
private CategoryNamespaceProvider $categoryNamespaceProvider,
private FileRelocationResolver $fileRelocationResolver,
private RenamedClassesCollector $renamedClassesCollector,
private RenamedClassesDataCollector $renamedClassesDataCollector,
private FileInfoDeletionAnalyzer $fileInfoDeletionAnalyzer
) {
}
@ -91,7 +91,7 @@ final class AddedFileWithNodesFactory
$classLike = clone $classLike;
$classLike->namespacedName = new FullyQualified($newClassName);
$this->renamedClassesCollector->addClassRename($oldClassName, $newClassName);
$this->renamedClassesDataCollector->addOldToNewClass($oldClassName, $newClassName);
return new AddedFileWithNodes($newFileDestination, $fileNodes);
}

View File

@ -469,6 +469,7 @@ final class NodeTypeResolver
if (! $renamedObjectType instanceof ObjectType) {
return $this->isObjectTypeOfObjectType($resolvedObjectType, $requiredObjectType);
}
if (! $this->isObjectTypeOfObjectType($renamedObjectType, $requiredObjectType)) {
return $this->isObjectTypeOfObjectType($resolvedObjectType, $requiredObjectType);
}

View File

@ -8,6 +8,9 @@ use PhpParser\Node as PhpParserNode;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\Type\ObjectType;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\BetterPhpDocParser\PhpDoc\SpacelessPhpDocTagNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
use Rector\Core\Configuration\Option;
@ -39,6 +42,15 @@ final class NameImportingPhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
public function enterNode(Node $node): ?Node
{
if ($node instanceof SpacelessPhpDocTagNode) {
return $this->enterSpacelessPhpDocTagNode($node);
}
if ($node instanceof DoctrineAnnotationTagValueNode) {
$this->processDoctrineAnnotationTagValueNode($node);
return $node;
}
if (! $node instanceof IdentifierTypeNode) {
return null;
}
@ -89,18 +101,20 @@ final class NameImportingPhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
if ($newNode->name !== $identifierTypeNode->name) {
return $newNode;
}
return $identifierTypeNode;
}
return $identifierTypeNode;
}
$this->useNodesToAddCollector->addUseImport($phpParserNode, $fullyQualifiedObjectType);
$this->useNodesToAddCollector->addUseImport($fullyQualifiedObjectType);
$newNode = new IdentifierTypeNode($fullyQualifiedObjectType->getShortName());
if ($newNode->name !== $identifierTypeNode->name) {
return $newNode;
}
return $identifierTypeNode;
}
@ -113,4 +127,73 @@ final class NameImportingPhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
return substr_count($fullyQualifiedObjectType->getClassName(), '\\') === 0;
}
private function processDoctrineAnnotationTagValueNode(
DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode
): void {
$identifierTypeNode = $doctrineAnnotationTagValueNode->identifierTypeNode;
$staticType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType(
$identifierTypeNode,
$this->currentPhpParserNode
);
if (! $staticType instanceof FullyQualifiedObjectType) {
if (! $staticType instanceof ObjectType) {
return;
}
$staticType = new FullyQualifiedObjectType($staticType->getClassName());
}
$shortentedIdentifierTypeNode = $this->processFqnNameImport(
$this->currentPhpParserNode,
$identifierTypeNode,
$staticType
);
if (! $shortentedIdentifierTypeNode instanceof IdentifierTypeNode) {
return;
}
$doctrineAnnotationTagValueNode->identifierTypeNode = $shortentedIdentifierTypeNode;
$doctrineAnnotationTagValueNode->markAsChanged();
}
private function enterSpacelessPhpDocTagNode(
SpacelessPhpDocTagNode $spacelessPhpDocTagNode
): SpacelessPhpDocTagNode | null {
if (! $spacelessPhpDocTagNode->value instanceof DoctrineAnnotationTagValueNode) {
return null;
}
// special case for doctrine annotation
if (! str_starts_with($spacelessPhpDocTagNode->name, '@')) {
return null;
}
$attributeClass = ltrim($spacelessPhpDocTagNode->name, '@\\');
$identifierTypeNode = new IdentifierTypeNode($attributeClass);
$staticType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType(
new IdentifierTypeNode($attributeClass),
$this->currentPhpParserNode
);
if (! $staticType instanceof FullyQualifiedObjectType) {
if (! $staticType instanceof ObjectType) {
return null;
}
$staticType = new FullyQualifiedObjectType($staticType->getClassName());
}
$importedName = $this->processFqnNameImport($this->currentPhpParserNode, $identifierTypeNode, $staticType);
if ($importedName !== null) {
$spacelessPhpDocTagNode->name = '@' . $importedName->name;
return $spacelessPhpDocTagNode;
}
return null;
}
}

View File

@ -7,6 +7,7 @@ namespace Rector\PhpAttribute\Printer;
use PhpParser\Node\Arg;
use PhpParser\Node\Attribute;
use PhpParser\Node\Scalar\String_;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -21,7 +22,9 @@ final class DoctrineAnnotationFactory
public function createFromAttribute(Attribute $attribute, string $className): DoctrineAnnotationTagValueNode
{
$items = $this->createItemsFromArgs($attribute->args);
return new DoctrineAnnotationTagValueNode($className, null, $items);
$identifierTypeNode = new IdentifierTypeNode($className);
return new DoctrineAnnotationTagValueNode($identifierTypeNode, null, $items);
}
/**

View File

@ -45,7 +45,7 @@ final class UseNodesToAddCollector implements NodeCollectorInterface
/**
* @param FullyQualifiedObjectType|AliasedObjectType $objectType
*/
public function addUseImport(Node $positionNode, ObjectType $objectType): void
public function addUseImport(ObjectType $objectType): void
{
$file = $this->currentFileProvider->getFile();
$smartFileInfo = $file->getSmartFileInfo();

View File

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Rector\PostRector\Rector;
use PhpParser\Node;
use Rector\PSR4\Collector\RenamedClassesCollector;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Renaming\NodeManipulator\ClassRenamer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -14,7 +14,7 @@ final class ClassRenamingPostRector extends AbstractPostRector
{
public function __construct(
private ClassRenamer $classRenamer,
private RenamedClassesCollector $renamedClassesCollector
private RenamedClassesDataCollector $renamedClassesDataCollector
) {
}
@ -26,7 +26,7 @@ final class ClassRenamingPostRector extends AbstractPostRector
public function enterNode(Node $node): ?Node
{
$oldToNewClasses = $this->renamedClassesCollector->getOldToNewClasses();
$oldToNewClasses = $this->renamedClassesDataCollector->getOldToNewClasses();
if ($oldToNewClasses === []) {
return $node;
}

View File

@ -8,6 +8,7 @@ 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;
@ -25,7 +26,8 @@ final class UseAddingPostRector extends AbstractPostRector
private UseImportsAdder $useImportsAdder,
private UseImportsRemover $useImportsRemover,
private UseNodesToAddCollector $useNodesToAddCollector,
private CurrentFileProvider $currentFileProvider
private CurrentFileProvider $currentFileProvider,
private RenamedClassesDataCollector $renamedClassesDataCollector
) {
}
@ -47,8 +49,10 @@ final class UseAddingPostRector extends AbstractPostRector
$functionUseImportTypes = $this->useNodesToAddCollector->getFunctionImportsByFileInfo($smartFileInfo);
$removedShortUses = $this->useNodesToAddCollector->getShortUsesByFileInfo($smartFileInfo);
$oldToNewClasses = $this->renamedClassesDataCollector->getOldToNewClasses();
// nothing to import or remove
if ($useImportTypes === [] && $functionUseImportTypes === [] && $removedShortUses === []) {
if ($useImportTypes === [] && $functionUseImportTypes === [] && $removedShortUses === [] && $oldToNewClasses === []) {
return $nodes;
}
@ -73,6 +77,8 @@ final class UseAddingPostRector extends AbstractPostRector
$nodes = $firstNode->stmts;
}
$removedShortUses = array_merge($removedShortUses, $this->renamedClassesDataCollector->getOldClasses());
// B. no namespace? add in the top
// first clean
$nodes = $this->useImportsRemover->removeImportsFromStmts($nodes, $removedShortUses);

View File

@ -17,15 +17,15 @@ use PHPStan\Type\StaticType;
use PHPStan\Type\StringType;
use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PSR4\Collector\RenamedClassesCollector;
use Rector\StaticTypeMapper\Contract\PhpParser\PhpParserNodeMapperInterface;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class NameNodeMapper implements PhpParserNodeMapperInterface
{
public function __construct(
private RenamedClassesCollector $renamedClassesCollector,
private RenamedClassesDataCollector $renamedClassesDataCollector,
private ReflectionProvider $reflectionProvider
) {
}
@ -62,7 +62,7 @@ final class NameNodeMapper implements PhpParserNodeMapperInterface
}
// to be existing class names
$oldToNewClasses = $this->renamedClassesCollector->getOldToNewClasses();
$oldToNewClasses = $this->renamedClassesDataCollector->getOldToNewClasses();
return in_array($name, $oldToNewClasses, true);
}

View File

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Php72\Rector\FuncCall\GetClassOnNullRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
$services = $containerConfigurator->services();
$services->set(GetClassOnNullRector::class);
};

View File

@ -59,11 +59,13 @@ final class UseImportsRemover
{
foreach ($use->uses as $usesKey => $useUse) {
foreach ($removedShortUses as $removedShortUse) {
if ($useUse->name->getLast() !== $removedShortUse) {
continue;
if ($useUse->name->getLast() === $removedShortUse) {
unset($use->uses[$usesKey]);
}
unset($use->uses[$usesKey]);
if ($useUse->name->toString() === $removedShortUse) {
unset($use->uses[$usesKey]);
}
}
}
}

View File

@ -6,6 +6,7 @@ namespace Rector\CodingStyle\ClassNameImport\ClassNameImportSkipVoter;
use PhpParser\Node;
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\PostRector\Collector\UseNodesToAddCollector;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
@ -19,7 +20,8 @@ use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class UsesClassNameImportSkipVoter implements ClassNameImportSkipVoterInterface
{
public function __construct(
private UseNodesToAddCollector $useNodesToAddCollector
private UseNodesToAddCollector $useNodesToAddCollector,
private RenamedClassesDataCollector $renamedClassesDataCollector
) {
}
@ -28,10 +30,14 @@ final class UsesClassNameImportSkipVoter implements ClassNameImportSkipVoterInte
$useImportTypes = $this->useNodesToAddCollector->getUseImportTypesByNode($node);
foreach ($useImportTypes as $useImportType) {
// if the class is renamed, the use import is no longer blocker
if ($this->renamedClassesDataCollector->hasOldClass($useImportType->getClassName())) {
continue;
}
if (! $useImportType->equals($fullyQualifiedObjectType) && $useImportType->areShortNamesEqual(
$fullyQualifiedObjectType
)
) {
)) {
return true;
}

View File

@ -9,7 +9,7 @@ use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
use Rector\PSR4\Collector\RenamedClassesCollector;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class ClassNameImportSkipper
@ -19,7 +19,7 @@ final class ClassNameImportSkipper
*/
public function __construct(
private array $classNameImportSkipVoters,
private RenamedClassesCollector $renamedClassesCollector
private RenamedClassesDataCollector $renamedClassesDataCollector
) {
}
@ -90,7 +90,7 @@ final class ClassNameImportSkipper
private function isJustRenamedClass(Name $name, UseUse $useUse): bool
{
// is in renamed classes? skip it
foreach ($this->renamedClassesCollector->getOldToNewClasses() as $oldClass => $newClass) {
foreach ($this->renamedClassesDataCollector->getOldToNewClasses() as $oldClass => $newClass) {
// is class being renamed in use imports?
if ($name->toString() !== $newClass) {
continue;

View File

@ -178,7 +178,7 @@ final class NameImporter
if ($parentNode instanceof FuncCall) {
$this->useNodesToAddCollector->addFunctionUseImport($name, $fullyQualifiedObjectType);
} else {
$this->useNodesToAddCollector->addUseImport($name, $fullyQualifiedObjectType);
$this->useNodesToAddCollector->addUseImport($fullyQualifiedObjectType);
}
}
}

View File

@ -1,36 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PSR4\Collector;
use Rector\Core\Configuration\RenamedClassesDataCollector;
/**
* @deprecated Merge with RenamedClassesDataCollector
*/
final class RenamedClassesCollector
{
/**
* @var array<string, string>
*/
private array $oldToNewClass = [];
public function __construct(
private RenamedClassesDataCollector $renamedClassesDataCollector
) {
}
public function addClassRename(string $oldClass, string $newClass): void
{
$this->oldToNewClass[$oldClass] = $newClass;
}
/**
* @return array<string, string>
*/
public function getOldToNewClasses(): array
{
return array_merge($this->oldToNewClass, $this->renamedClassesDataCollector->getOldToNewClasses());
}
}

View File

@ -13,6 +13,16 @@ final class RenamedClassesDataCollector
*/
private array $oldToNewClasses = [];
public function addOldToNewClass(string $oldClass, string $newClass): void
{
$this->oldToNewClasses[$oldClass] = $newClass;
}
public function hasOldClass(string $oldClass): bool
{
return isset($this->oldToNewClasses[$oldClass]);
}
/**
* @param array<string, string> $oldToNewClasses
*/
@ -40,4 +50,12 @@ final class RenamedClassesDataCollector
return new ObjectType($renamedClassName);
}
/**
* @return string[]
*/
public function getOldClasses(): array
{
return array_keys($this->oldToNewClasses);
}
}

View File

@ -8,7 +8,6 @@ use Nette\Utils\Strings;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Contract\Rector\NonPhpRectorInterface;
use Rector\PSR4\Collector\RenamedClassesCollector;
use Symplify\RuleDocGenerator\Contract\ConfigurableRuleInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -41,7 +40,6 @@ final class RenameClassNonPhpRector implements NonPhpRectorInterface, Configurab
public function __construct(
private RenamedClassesDataCollector $renamedClassesDataCollector,
private RenamedClassesCollector $renamedClassesCollector
) {
}
@ -133,11 +131,7 @@ CODE_SAMPLE
*/
private function getRenameClasses(): array
{
return array_merge(
$this->renameClasses,
$this->renamedClassesDataCollector->getOldToNewClasses(),
$this->renamedClassesCollector->getOldToNewClasses()
);
return array_merge($this->renameClasses, $this->renamedClassesDataCollector->getOldToNewClasses());
}
private function createOldClassRegex(string $oldClass): string

View File

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Symfony\Component\Routing\Annotation;
if (class_exists('Symfony\Component\Routing\Annotation\Route')) {
return;
}
class Route
{
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Tests\Issues\Issue6496;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class AutoImportDocBlockTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configure_rule.php';
}
}

View File

@ -0,0 +1,27 @@
<?php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
* @Route("/someUrl")
*/
class SomeController extends Controller
{
}
?>
-----
<?php
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
* @Route("/someUrl")
*/
class SomeController extends Controller
{
}
?>

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Symfony\Rector\ClassMethod\ReplaceSensioRouteAnnotationWithSymfonyRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
$parameters->set(Option::IMPORT_DOC_BLOCKS, true);
$services = $containerConfigurator->services();
$services->set(ReplaceSensioRouteAnnotationWithSymfonyRector::class);
};