Skip to content

Commit

Permalink
[PHP 8.0] Avoid duplicating attributed annotations (#212)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jun 13, 2021
1 parent 25821f6 commit 6888049
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rector\Tests\Php80\Rector\Class_\DoctrineAnnotationClassToAttributeRector\FixtureShouldNotRemoveAnnotation;

use Attribute;

/**
* @Annotation
*/
#[Attribute]
final class SkipAlreadyAdded
{
}
34 changes: 34 additions & 0 deletions rules/Php80/NodeAnalyzer/PhpAttributeAnalyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Rector\Php80\NodeAnalyzer;

use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\NodeNameResolver\NodeNameResolver;

final class PhpAttributeAnalyzer
{
public function __construct(
private NodeNameResolver $nodeNameResolver
) {
}

public function hasPhpAttribute(Property | ClassLike | ClassMethod | Param $node, string $attributeClass): bool
{
foreach ($node->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attribute) {
if (! $this->nodeNameResolver->isName($attribute->name, $attributeClass)) {
continue;
}

return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Rector\BetterPhpDocParser\ValueObject\PhpDoc\DoctrineAnnotation\CurlyListNode;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer;
use Rector\Php80\NodeFactory\AttributeFlagFactory;
use Rector\PhpAttribute\Printer\PhpAttributeGroupFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
Expand Down Expand Up @@ -51,12 +52,18 @@ final class DoctrineAnnotationClassToAttributeRector extends AbstractRector impl
'ANNOTATION' => 'TARGET_CLASS',
];

/**
* @var string
*/
private const ATTRIBUTE = 'Attribute';

private bool $shouldRemoveAnnotations = true;

public function __construct(
private PhpDocTagRemover $phpDocTagRemover,
private AttributeFlagFactory $attributeFlagFactory,
private PhpAttributeGroupFactory $phpAttributeGroupFactory
private PhpAttributeGroupFactory $phpAttributeGroupFactory,
private PhpAttributeAnalyzer $phpAttributeAnalyzer
) {
}

Expand Down Expand Up @@ -111,7 +118,7 @@ public function refactor(Node $node): ?Node
return null;
}

if (! $phpDocInfo->hasByNames(['Annotation', 'annotation'])) {
if ($this->shouldSkipClass($phpDocInfo, $node)) {
return null;
}

Expand All @@ -120,7 +127,7 @@ public function refactor(Node $node): ?Node
$this->phpDocTagRemover->removeByName($phpDocInfo, 'Annotation');
}

$attributeGroup = $this->phpAttributeGroupFactory->createFromClass('Attribute');
$attributeGroup = $this->phpAttributeGroupFactory->createFromClass(self::ATTRIBUTE);
$this->decorateTarget($phpDocInfo, $attributeGroup);

foreach ($node->getProperties() as $property) {
Expand Down Expand Up @@ -179,7 +186,7 @@ private function resolveFlags(array $targetValues): array
continue;
}

$flags[] = $this->nodeFactory->createClassConstFetch('Attribute', $constant);
$flags[] = $this->nodeFactory->createClassConstFetch(self::ATTRIBUTE, $constant);
}

return $flags;
Expand Down Expand Up @@ -214,4 +221,14 @@ private function decorateTarget(PhpDocInfo $phpDocInfo, AttributeGroup $attribut

$attributeGroup->attrs[0]->args[] = new Arg($flagCollection);
}

private function shouldSkipClass(PhpDocInfo $phpDocInfo, Class_ $class): bool
{
if (! $phpDocInfo->hasByNames(['Annotation', 'annotation'])) {
return true;
}

// has attribute? skip it
return $this->phpAttributeAnalyzer->hasPhpAttribute($class, self::ATTRIBUTE);
}
}

0 comments on commit 6888049

Please sign in to comment.