Skip to content

Commit

Permalink
Fix doc importing on Doctrine annotation class rename (#264)
Browse files Browse the repository at this point in the history
Co-authored-by: GitHub Action <action@github.com>
  • Loading branch information
TomasVotruba and actions-user committed Jun 22, 2021
1 parent a8ccfeb commit a41384b
Show file tree
Hide file tree
Showing 30 changed files with 279 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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); // []
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Rector\BetterPhpDocParser\PhpDoc;

use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDoc\DoctrineAnnotation\AbstractValuesAwareNode;
use Stringable;

Expand All @@ -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
Expand Down Expand Up @@ -46,8 +47,8 @@ public function __toString(): string
return sprintf('(%s)', $itemContents);
}

public function getAnnotationClass(): string
public function hasClassName(string $className): bool
{
return $this->annotationClass;
return $this->identifierTypeNode->name === $className;
}
}
8 changes: 4 additions & 4 deletions packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,13 @@ public function getByAnnotationClass(string $desiredClass): ?DoctrineAnnotationT

$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;
}
}
Expand Down Expand Up @@ -348,7 +348,7 @@ public function addTagValueNode(PhpDocTagValueNode $phpDocTagValueNode): void
{
if ($phpDocTagValueNode instanceof DoctrineAnnotationTagValueNode) {
$spacelessPhpDocTagNode = new SpacelessPhpDocTagNode(
'@\\' . $phpDocTagValueNode->getAnnotationClass(),
'@\\' . $phpDocTagValueNode->identifierTypeNode,
$phpDocTagValueNode
);
$this->addPhpDocTagNode($spacelessPhpDocTagNode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,9 @@ private function processDoctrineToMany(
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ public function removeByName(PhpDocInfo $phpDocInfo, string $name): void
}

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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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;
Expand Down Expand Up @@ -155,7 +156,7 @@ private function transformGenericTagValueNodesToDoctrineAnnotationTagValueNodes(
$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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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;
Expand Down Expand Up @@ -109,6 +110,7 @@ private function parseNestedDoctrineAnnotationTagValueNode(
$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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ public function getValuesWithExplicitSilentAndWithoutQuotes(): array
return $explicitKeysValues;
}

public function markAsChanged(): void
{
$this->hasChanged = true;
}

/**
* @param mixed|string $value
* @return mixed|string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Rector\BetterPhpDocParser\ValueObjectFactory\PhpDocNode\Symfony;

use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;

final class SymfonyRouteTagValueNodeFactory
Expand All @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
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;
Expand All @@ -25,7 +25,7 @@ public function __construct(
private BetterNodeFinder $betterNodeFinder,
private CategoryNamespaceProvider $categoryNamespaceProvider,
private FileRelocationResolver $fileRelocationResolver,
private RenamedClassesCollector $renamedClassesCollector,
private RenamedClassesDataCollector $renamedClassesDataCollector,
private FileInfoDeletionAnalyzer $fileInfoDeletionAnalyzer
) {
}
Expand Down Expand Up @@ -91,7 +91,7 @@ public function createWithDesiredGroup(
$classLike = clone $classLike;
$classLike->namespacedName = new FullyQualified($newClassName);

$this->renamedClassesCollector->addClassRename($oldClassName, $newClassName);
$this->renamedClassesDataCollector->addOldToNewClass($oldClassName, $newClassName);

return new AddedFileWithNodes($newFileDestination, $fileNodes);
}
Expand Down
1 change: 1 addition & 0 deletions packages/NodeTypeResolver/NodeTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ private function resolveObjectType(ObjectType $resolvedObjectType, ObjectType $r
if (! $renamedObjectType instanceof ObjectType) {
return $this->isObjectTypeOfObjectType($resolvedObjectType, $requiredObjectType);
}

if (! $this->isObjectTypeOfObjectType($renamedObjectType, $requiredObjectType)) {
return $this->isObjectTypeOfObjectType($resolvedObjectType, $requiredObjectType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
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;
Expand Down Expand Up @@ -39,6 +42,15 @@ public function beforeTraverse(Node $node): void

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;
}
Expand Down Expand Up @@ -89,18 +101,20 @@ private function processFqnNameImport(
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;
}

Expand All @@ -113,4 +127,73 @@ private function shouldSkipShortClassName(FullyQualifiedObjectType $fullyQualifi

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;
}
}
5 changes: 4 additions & 1 deletion packages/PhpAttribute/Printer/DoctrineAnnotationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
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;
Expand All @@ -21,7 +22,9 @@ public function __construct(
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);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/PostRector/Collector/UseNodesToAddCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function isActive(): bool
/**
* @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();
Expand Down
6 changes: 3 additions & 3 deletions packages/PostRector/Rector/ClassRenamingPostRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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;
Expand All @@ -14,7 +14,7 @@ final class ClassRenamingPostRector extends AbstractPostRector
{
public function __construct(
private ClassRenamer $classRenamer,
private RenamedClassesCollector $renamedClassesCollector
private RenamedClassesDataCollector $renamedClassesDataCollector
) {
}

Expand All @@ -26,7 +26,7 @@ public function getPriority(): int

public function enterNode(Node $node): ?Node
{
$oldToNewClasses = $this->renamedClassesCollector->getOldToNewClasses();
$oldToNewClasses = $this->renamedClassesDataCollector->getOldToNewClasses();
if ($oldToNewClasses === []) {
return $node;
}
Expand Down

0 comments on commit a41384b

Please sign in to comment.