Skip to content

Commit

Permalink
Add the TemplateExtends, TemplateImplements and TemplateUse attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-granados committed Feb 23, 2024
1 parent 73299b3 commit 02eaae6
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 11 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ These are the available attributes and their corresponding PHPDoc annotations:
| [Template](https://github.com/php-static-analysis/attributes/blob/main/doc/Template.md) | `@template` |
| [TemplateContravariant](https://github.com/php-static-analysis/attributes/blob/main/doc/TemplateContravariant.md) | `@template-contravariant` |
| [TemplateCovariant](https://github.com/php-static-analysis/attributes/blob/main/doc/TemplateCovariant.md) | `@template-covariant` |
| [TemplateExtends](https://github.com/php-static-analysis/attributes/blob/main/doc/TemplateExtends.md) | `@extends` `@template-extends` |
| [TemplateImplements](https://github.com/php-static-analysis/attributes/blob/main/doc/TemplateImplements.md) | `@implements` `@template-implements` |
| [TemplateUse](https://github.com/php-static-analysis/attributes/blob/main/doc/TemplateUse.md) | `@use` `@template-use` |
| [Type](https://github.com/php-static-analysis/attributes/blob/main/doc/Type.md) | `@var` `@return` |

### Location of Param attributes
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"require": {
"php": ">=8.0",
"cweagans/composer-patches": "^1.7",
"php-static-analysis/attributes": "^0.1.10 || dev-main",
"php-static-analysis/attributes": "^0.1.11 || dev-main",
"rector/rector": "^0.19 || ^1.0"
},
"require-dev": {
Expand Down
9 changes: 9 additions & 0 deletions config/sets/php-static-analysis-annotations-to-attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
use PhpStaticAnalysis\Attributes\PropertyWrite;
use PhpStaticAnalysis\Attributes\TemplateContravariant;
use PhpStaticAnalysis\Attributes\TemplateCovariant;
use PhpStaticAnalysis\Attributes\TemplateExtends;
use PhpStaticAnalysis\Attributes\TemplateImplements;
use PhpStaticAnalysis\Attributes\TemplateUse;
use Rector\Config\RectorConfig;
use Rector\Php80\ValueObject\AnnotationToAttribute;
use PhpStaticAnalysis\Attributes\IsReadOnly;
Expand All @@ -25,6 +28,8 @@
AnnotationsToAttributesRector::class,
[
new AnnotationToAttribute('deprecated', Deprecated::class),
new AnnotationToAttribute('extends', TemplateExtends::class),
new AnnotationToAttribute('implements', TemplateImplements::class),
new AnnotationToAttribute('internal', Internal::class),
new AnnotationToAttribute('method', Method::class),
new AnnotationToAttribute('mixin', Mixin::class),
Expand All @@ -37,6 +42,10 @@
new AnnotationToAttribute('template', Template::class),
new AnnotationToAttribute('template_contravariant', TemplateContravariant::class),
new AnnotationToAttribute('template_covariant', TemplateCovariant::class),
new AnnotationToAttribute('template_extends', TemplateExtends::class),
new AnnotationToAttribute('template_implements', TemplateImplements::class),
new AnnotationToAttribute('template_use', TemplateUse::class),
new AnnotationToAttribute('use', TemplateUse::class),
new AnnotationToAttribute('var', Type::class),
'addParamAttributeOnParameters' => false,
'useTypeAttributeForReturnAnnotation' => false,
Expand Down
44 changes: 34 additions & 10 deletions src/AnnotationsToAttributesRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
use PHPStan\PhpDocParser\Ast\PhpDoc\DeprecatedTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ImplementsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\UsesTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PhpStaticAnalysis\Attributes\Param;
Expand Down Expand Up @@ -165,19 +168,17 @@ public function getNodeTypes(): array
public function refactor(Node $node): ?Node
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($node);
if (!$phpDocInfo instanceof PhpDocInfo) {
return null;
}

$attributeGroups = $this->processAnnotations($phpDocInfo);

if ($attributeGroups === []) {
return null;
$attributeGroups = [];
if ($phpDocInfo instanceof PhpDocInfo) {
$attributeGroups = $this->processAnnotations($phpDocInfo);
}

$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node);
if ($attributeGroups !== []) {
$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node);

$this->attributeGroupNamedArgumentManipulator->decorate($attributeGroups);
$this->attributeGroupNamedArgumentManipulator->decorate($attributeGroups);
}

if ($this->addParamAttributeOnParameters &&
($node instanceof Stmt\ClassMethod || $node instanceof Stmt\Function_)) {
Expand Down Expand Up @@ -207,7 +208,27 @@ public function refactor(Node $node): ?Node
}
}

$node->attrGroups = array_merge($node->attrGroups, $attributeGroups);
if ($node instanceof Stmt\Class_) {
foreach ($node->stmts as $stmt) {
if ($stmt instanceof Stmt\TraitUse) {
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($stmt);
if ($phpDocInfo instanceof PhpDocInfo) {
$useAttributeGroups = $this->processAnnotations($phpDocInfo);

if ($useAttributeGroups !== []) {
$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($stmt);

$this->attributeGroupNamedArgumentManipulator->decorate($useAttributeGroups);
$attributeGroups = array_merge($attributeGroups, $useAttributeGroups);
}
}
}
}
}

if ($attributeGroups !== []) {
$node->attrGroups = array_merge($node->attrGroups, $attributeGroups);
}

return $node;
}
Expand Down Expand Up @@ -258,8 +279,11 @@ private function processAnnotations(PhpDocInfo $phpDocInfo): array
];
$attributeComment = $tagValueNode->description;
break;
case $tagValueNode instanceof ExtendsTagValueNode:
case $tagValueNode instanceof ImplementsTagValueNode:
case $tagValueNode instanceof MixinTagValueNode:
case $tagValueNode instanceof ReturnTagValueNode:
case $tagValueNode instanceof UsesTagValueNode:
case $tagValueNode instanceof VarTagValueNode:
$args = [
new Node\Arg(new Scalar\String_((string)($tagValueNode->type)))
Expand Down
69 changes: 69 additions & 0 deletions tests/Fixture/TemplateExtendsAttributeTest.php.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Template;

#[Template('T')]
class TemplateClass
{
}

/**
* @codeCoverageIgnore
* @extends TemplateClass<int> this is the extended class
*/
#[Property(name:'string')]
class TemplateExtendsAttributeTest extends TemplateClass
{
}

/**
* @template-extends TemplateClass<int>
*/
class TemplateExtendsAttributeTest2 extends TemplateClass
{
}

/**
* @phpstan-extends TemplateClass<int>
*/
class TemplateExtendsAttributeTest3 extends TemplateClass
{
}

?>
-----
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Template;

#[Template('T')]
class TemplateClass
{
}

/**
* @codeCoverageIgnore
*/
#[Property(name:'string')]
#[\PhpStaticAnalysis\Attributes\TemplateExtends('TemplateClass<int>')] // this is the extended class
class TemplateExtendsAttributeTest extends TemplateClass
{
}

#[\PhpStaticAnalysis\Attributes\TemplateExtends('TemplateClass<int>')]
class TemplateExtendsAttributeTest2 extends TemplateClass
{
}

#[\PhpStaticAnalysis\Attributes\TemplateExtends('TemplateClass<int>')]
class TemplateExtendsAttributeTest3 extends TemplateClass
{
}

?>
69 changes: 69 additions & 0 deletions tests/Fixture/TemplateImplementsAttributeTest.php.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Template;

#[Template('T')]
interface TemplateInterface
{
}

/**
* @codeCoverageIgnore
* @implements TemplateInterface<int> this is the implemented interface
*/
#[Property(name:'string')]
class TemplateImplementsAttributeTest implements TemplateInterface
{
}

/**
* @template-implements TemplateInterface<int>
*/
class TemplateImplementsAttributeTest2 implements TemplateInterface
{
}

/**
* @phpstan-implements TemplateInterface<int>
*/
class TemplateImplementsAttributeTest3 implements TemplateInterface
{
}

?>
-----
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Template;

#[Template('T')]
interface TemplateInterface
{
}

/**
* @codeCoverageIgnore
*/
#[Property(name:'string')]
#[\PhpStaticAnalysis\Attributes\TemplateImplements('TemplateInterface<int>')] // this is the implemented interface
class TemplateImplementsAttributeTest implements TemplateInterface
{
}

#[\PhpStaticAnalysis\Attributes\TemplateImplements('TemplateInterface<int>')]
class TemplateImplementsAttributeTest2 implements TemplateInterface
{
}

#[\PhpStaticAnalysis\Attributes\TemplateImplements('TemplateInterface<int>')]
class TemplateImplementsAttributeTest3 implements TemplateInterface
{
}

?>
75 changes: 75 additions & 0 deletions tests/Fixture/TemplateUseAttributeTest.php.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Template;

#[Template('T')]
trait TemplateTrait
{
}

#[Property(name:'string')]
class TemplateUseAttributeTest
{
/**
* @codeCoverageIgnore
* @use TemplateTrait<int> this is the used trait
*/
use TemplateTrait;
}

class TemplateUseAttributeTest2
{
/**
* @template-use TemplateTrait<int>
*/
use TemplateTrait;
}

class TemplateUseAttributeTest3
{
/**
* @phpstan-use TemplateTrait<int>
*/
use TemplateTrait;
}

?>
-----
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Template;

#[Template('T')]
trait TemplateTrait
{
}

#[Property(name:'string')]
#[\PhpStaticAnalysis\Attributes\TemplateUse('TemplateTrait<int>')] // this is the used trait
class TemplateUseAttributeTest
{
/**
* @codeCoverageIgnore
*/
use TemplateTrait;
}

#[\PhpStaticAnalysis\Attributes\TemplateUse('TemplateTrait<int>')]
class TemplateUseAttributeTest2
{
use TemplateTrait;
}

#[\PhpStaticAnalysis\Attributes\TemplateUse('TemplateTrait<int>')]
class TemplateUseAttributeTest3
{
use TemplateTrait;
}

?>

0 comments on commit 02eaae6

Please sign in to comment.