Skip to content

Commit

Permalink
Add the Property attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-granados committed Feb 15, 2024
1 parent f05ab43 commit fcda73e
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 1 deletion.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,22 @@ return RectorConfig::configure()
);
```

### Attribute to use for the type of class properties

By default `Type` attributes are added to define the type of class properties. It is possible to use the `Property` attribute instead. To activate this option, add this code to your configuration:

```php
use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector;
use Rector\Config\RectorConfig;
...

return RectorConfig::configure()
...
->withConfiguredRule(
AnnotationsToAttributesRector::class,
[
'usePropertyAttributeForVarAnnotation' => true,
]
);
```

2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"prefer-stable": true,
"require": {
"php": ">=8.0",
"php-static-analysis/attributes": "^0.1.2 || dev-main",
"php-static-analysis/attributes": "^0.1.3 || dev-main",
"rector/rector": "^0.19 || ^1.0"
},
"require-dev": {
Expand Down
3 changes: 3 additions & 0 deletions config/sets/php-static-analysis-annotations-to-attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Rector\Php80\ValueObject\AnnotationToAttribute;
use PhpStaticAnalysis\Attributes\IsReadOnly;
use PhpStaticAnalysis\Attributes\Param;
use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Returns;
use PhpStaticAnalysis\Attributes\Template;
use PhpStaticAnalysis\Attributes\Type;
Expand All @@ -16,12 +17,14 @@
AnnotationsToAttributesRector::class,
[
new AnnotationToAttribute('param', Param::class),
new AnnotationToAttribute('property', Property::class),
new AnnotationToAttribute('readonly', IsReadOnly::class),
new AnnotationToAttribute('return', Returns::class),
new AnnotationToAttribute('template', Template::class),
new AnnotationToAttribute('var', Type::class),
'addParamAttributeOnParameters' => false,
'useTypeAttributeForReturnAnnotation' => false,
'usePropertyAttributeForVarAnnotation' => false,
]
);
};
20 changes: 20 additions & 0 deletions src/AnnotationsToAttributesRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
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\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PhpStaticAnalysis\Attributes\Param;
use PhpStaticAnalysis\Attributes\Property;
use PhpStaticAnalysis\Attributes\Returns;
use PhpStaticAnalysis\Attributes\Type;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
Expand All @@ -44,6 +46,8 @@ final class AnnotationsToAttributesRector extends AbstractRector implements Conf

private bool $useTypeAttributeForReturnAnnotation = false;

private bool $usePropertyAttributeForVarAnnotation = false;

public function __construct(
private PhpDocTagRemover $phpDocTagRemover,
private AttributeGroupNamedArgumentManipulator $attributeGroupNamedArgumentManipulator,
Expand Down Expand Up @@ -117,6 +121,8 @@ public function configure(array $configuration): void
$this->addParamAttributeOnParameters = $value;
} elseif ($key == 'useTypeAttributeForReturnAnnotation') {
$this->useTypeAttributeForReturnAnnotation = $value;
} elseif ($key == 'usePropertyAttributeForVarAnnotation') {
$this->usePropertyAttributeForVarAnnotation = $value;
}
}
if ($this->useTypeAttributeForReturnAnnotation) {
Expand All @@ -125,6 +131,12 @@ public function configure(array $configuration): void
new AnnotationToAttribute('return', Type::class);
}
}
if ($this->usePropertyAttributeForVarAnnotation) {
if (isset($this->annotationsToAttributes['var'])) {
$this->annotationsToAttributes['var'] =
new AnnotationToAttribute('var', Property::class);
}
}
}

#[Returns('array<class-string<Node>>')]
Expand Down Expand Up @@ -220,6 +232,14 @@ private function processAnnotations(PhpDocInfo $phpDocInfo): array
)
];
break;
case $tagValueNode instanceof PropertyTagValueNode:
$args = [
new Node\Arg(
value: new Scalar\String_((string)($tagValueNode->type)),
name: new Node\Identifier(substr($tagValueNode->propertyName, 1))
)
];
break;
case $tagValueNode instanceof ReturnTagValueNode:
case $tagValueNode instanceof VarTagValueNode:
$args = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace test\PhpStaticAnalysis\RectorRule;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class AnnotationsToAttributesWithPropertyAttributeForVarRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public static function provideData(): Iterator
{
yield [__DIR__ . '/SpecialFixture/PropertyAttributeTestForVarAnnotation.php.inc'];
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured-rule-with-property-attribute-for-var.php';
}
}
37 changes: 37 additions & 0 deletions tests/Fixture/PropertyAttributeTest.php.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Template;

/**
* @deprecated
* @property string $name
* @psalm-property int $num
* @phpstan-property string[] $index
*/
#[Template('T')]
class PropertyAttributeTest
{
}

?>
-----
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\Template;

/**
* @deprecated
*/
#[Template('T')]
#[\PhpStaticAnalysis\Attributes\Property(name: 'string')]
#[\PhpStaticAnalysis\Attributes\Property(num: 'int')]
#[\PhpStaticAnalysis\Attributes\Property(index: 'string[]')]
class PropertyAttributeTest
{
}

?>
28 changes: 28 additions & 0 deletions tests/SpecialFixture/ParamAttributeTestWithParamOnParam.php.inc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ class ParamAttributeTestWithParamOnParam
{
return $name1 . $name2;
}

/**
* @psalm-param string $name
*/
public function getPsalmName($name)
{
return $name;
}

/**
* @phpstan-param string $name
*/
public function getPHPStanName($name)
{
return $name;
}
}

/**
Expand Down Expand Up @@ -106,6 +122,18 @@ class ParamAttributeTestWithParamOnParam
{
return $name1 . $name2;
}

public function getPsalmName(#[\PhpStaticAnalysis\Attributes\Param('string')]
$name)
{
return $name;
}

public function getPHPStanName(#[\PhpStaticAnalysis\Attributes\Param('string')]
$name)
{
return $name;
}
}

function getName(#[\PhpStaticAnalysis\Attributes\Param('string')]
Expand Down
67 changes: 67 additions & 0 deletions tests/SpecialFixture/PropertyAttributeTestForVarAnnotation.php.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\IsReadOnly;

class PropertyAttributeTestForVarAnnotation
{
/**
* @var string
*/
public $name;

/**
* @deprecated
* @var string
*/
public $anotherName;

/**
* @var string
*/
#[IsReadOnly]
public $otherName;

/**
* @psalm-var string
*/
public $psalmName;

/**
* @phpstan-var string
*/
public $phpstanName;
}

?>
-----
<?php

namespace test\PhpStaticAnalysis\RectorRule\Fixture;

use PhpStaticAnalysis\Attributes\IsReadOnly;

class PropertyAttributeTestForVarAnnotation
{
#[\PhpStaticAnalysis\Attributes\Property('string')]
public $name;

/**
* @deprecated
*/
#[\PhpStaticAnalysis\Attributes\Property('string')]
public $anotherName;

#[IsReadOnly]
#[\PhpStaticAnalysis\Attributes\Property('string')]
public $otherName;

#[\PhpStaticAnalysis\Attributes\Property('string')]
public $psalmName;

#[\PhpStaticAnalysis\Attributes\Property('string')]
public $phpstanName;
}

?>
19 changes: 19 additions & 0 deletions tests/config/configured-rule-with-property-attribute-for-var.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector;
use PhpStaticAnalysis\RectorRule\Set\PhpStaticAnalysisSetList;
use Rector\Config\RectorConfig;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->sets([
PhpStaticAnalysisSetList::ANNOTATIONS_TO_ATTRIBUTES
]);
$rectorConfig->ruleWithConfiguration(
AnnotationsToAttributesRector::class,
[
'usePropertyAttributeForVarAnnotation' => true,
]
);
};

0 comments on commit fcda73e

Please sign in to comment.