Skip to content

Commit 19cdb95

Browse files
Add Immutable attribute and the possibility to exclude some annotations
1 parent c35515d commit 19cdb95

8 files changed

+188
-5
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,29 @@ return RectorConfig::configure()
108108
);
109109
```
110110

111+
If you want to replace most annotations but exclude a few, you can use the `excludeAnnotations` config parameter like this:
112+
113+
```php
114+
use Rector\Config\RectorConfig;
115+
use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector;
116+
117+
return RectorConfig::configure()
118+
->withConfiguredRule(
119+
AnnotationsToAttributesRector::class,
120+
[
121+
'excludeAnnotations' => ['throws', 'deprecated'],
122+
]
123+
);
124+
```
125+
126+
That would convert all annotations except `@throws` and `@deprecated`
127+
111128
These are the available attributes and their corresponding PHPDoc annotations:
112129

113130
| Attribute | PHPDoc Annotations |
114131
|-------------------------------------------------------------------------------------------------------------------|--------------------|
115132
| [Deprecated](https://github.com/php-static-analysis/attributes/blob/main/doc/Deprecated.md) | `@deprecated` |
133+
| [Immmutable](https://github.com/php-static-analysis/attributes/blob/main/doc/Immmutable.md) | `@immmutable` |
116134
| [Impure](https://github.com/php-static-analysis/attributes/blob/main/doc/Impure.md) | `@impure` |
117135
| [Internal](https://github.com/php-static-analysis/attributes/blob/main/doc/Internal.md) | `@internal` |
118136
| [IsReadOnly](https://github.com/php-static-analysis/attributes/blob/main/doc/IsReadOnly.md) | `@readonly` |

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"require": {
2929
"php": ">=8.0",
3030
"cweagans/composer-patches": "^1.7",
31-
"php-static-analysis/attributes": "^0.1.16 || dev-main",
31+
"php-static-analysis/attributes": "^0.1.17 || dev-main",
3232
"rector/rector": "^0.19 || ^1.0"
3333
},
3434
"require-dev": {

config/sets/php-static-analysis-annotations-to-attributes.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
declare(strict_types=1);
44

55
use PhpStaticAnalysis\Attributes\Deprecated;
6+
use PhpStaticAnalysis\Attributes\Immutable;
67
use PhpStaticAnalysis\Attributes\Impure;
78
use PhpStaticAnalysis\Attributes\Internal;
89
use PhpStaticAnalysis\Attributes\Method;
@@ -36,6 +37,7 @@
3637
[
3738
new AnnotationToAttribute('deprecated', Deprecated::class),
3839
new AnnotationToAttribute('extends', TemplateExtends::class),
40+
new AnnotationToAttribute('immutable', Immutable::class),
3941
new AnnotationToAttribute('impure', Impure::class),
4042
new AnnotationToAttribute('implements', TemplateImplements::class),
4143
new AnnotationToAttribute('internal', Internal::class),
@@ -65,6 +67,7 @@
6567
'addParamAttributeOnParameters' => false,
6668
'useTypeAttributeForReturnAnnotation' => false,
6769
'usePropertyAttributeForVarAnnotation' => false,
70+
'excludeAnnotations' => [],
6871
]
6972
);
7073
};

src/AnnotationsToAttributesRector.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,22 @@ public function addArrays(array $array1, array $array2): array
124124
/**
125125
* @psalm-suppress MoreSpecificImplementedParamType
126126
*/
127-
#[Param(configuration: '(AnnotationToAttribute|bool)[]')]
127+
#[Param(configuration: '(AnnotationToAttribute|bool|string[])[]')]
128128
public function configure(array $configuration): void
129129
{
130+
$excludedAnnotations = [];
130131
foreach ($configuration as $key => $value) {
131132
if ($value instanceof AnnotationToAttribute) {
132133
$tag = str_replace('_', '-', $value->getTag());
133134
$this->annotationsToAttributes[$tag] = $value;
134-
} elseif ($key == 'addParamAttributeOnParameters') {
135+
} elseif (is_bool($value) && $key == 'addParamAttributeOnParameters') {
135136
$this->addParamAttributeOnParameters = $value;
136-
} elseif ($key == 'useTypeAttributeForReturnAnnotation') {
137+
} elseif (is_bool($value) && $key == 'useTypeAttributeForReturnAnnotation') {
137138
$this->useTypeAttributeForReturnAnnotation = $value;
138-
} elseif ($key == 'usePropertyAttributeForVarAnnotation') {
139+
} elseif (is_bool($value) && $key == 'usePropertyAttributeForVarAnnotation') {
139140
$this->usePropertyAttributeForVarAnnotation = $value;
141+
} elseif (is_array($value) && $key == 'excludeAnnotations') {
142+
$excludedAnnotations = $value;
140143
}
141144
}
142145
if ($this->useTypeAttributeForReturnAnnotation) {
@@ -151,6 +154,11 @@ public function configure(array $configuration): void
151154
new AnnotationToAttribute('var', Property::class);
152155
}
153156
}
157+
foreach ($excludedAnnotations as $excludedAnnotation) {
158+
if (isset($this->annotationsToAttributes[$excludedAnnotation])) {
159+
unset($this->annotationsToAttributes[$excludedAnnotation]);
160+
}
161+
}
154162
}
155163

156164
#[Returns('array<class-string<Node>>')]

tests/ExcludeAnnotationsTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace test\PhpStaticAnalysis\RectorRule;
6+
7+
use Iterator;
8+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
9+
10+
final class ExcludeAnnotationsTest extends AbstractRectorTestCase
11+
{
12+
/**
13+
* @dataProvider provideData()
14+
*/
15+
public function test(string $filePath): void
16+
{
17+
$this->doTestFile($filePath);
18+
}
19+
20+
public static function provideData(): Iterator
21+
{
22+
yield [__DIR__ . '/SpecialFixture/ExcludeAnnotationsTest.php.inc'];
23+
}
24+
25+
public function provideConfigFilePath(): string
26+
{
27+
return __DIR__ . '/config/configured-rule-with-exclude-annotations.php';
28+
}
29+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace test\PhpStaticAnalysis\RectorRule\Fixture;
4+
5+
use PhpStaticAnalysis\Attributes\Param;
6+
7+
/**
8+
* @codeCoverageIgnore
9+
* @immutable all properties are read only
10+
*/
11+
class ImmutableAttributeTest
12+
{
13+
}
14+
15+
/**
16+
* @psalm-immutable
17+
*/
18+
class ImmutableAttributePsalmTest
19+
{
20+
}
21+
22+
/**
23+
* @phpstan-immutable
24+
*/
25+
class ImmutableAttributePHPStanTest
26+
{
27+
}
28+
29+
?>
30+
-----
31+
<?php
32+
33+
namespace test\PhpStaticAnalysis\RectorRule\Fixture;
34+
35+
use PhpStaticAnalysis\Attributes\Param;
36+
37+
/**
38+
* @codeCoverageIgnore
39+
*/
40+
#[\PhpStaticAnalysis\Attributes\Immutable] // all properties are read only
41+
class ImmutableAttributeTest
42+
{
43+
}
44+
45+
#[\PhpStaticAnalysis\Attributes\Immutable]
46+
class ImmutableAttributePsalmTest
47+
{
48+
}
49+
50+
#[\PhpStaticAnalysis\Attributes\Immutable]
51+
class ImmutableAttributePHPStanTest
52+
{
53+
}
54+
55+
?>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace test\PhpStaticAnalysis\RectorRule\Fixture;
4+
5+
use Exception;
6+
7+
/**
8+
* @deprecated
9+
* @template T
10+
*/
11+
class ExcludeAnnotationsTest
12+
{
13+
/**
14+
* @var string
15+
*/
16+
public $name;
17+
18+
/**
19+
* @throws Exception
20+
*/
21+
public function throwsException()
22+
{
23+
}
24+
}
25+
26+
?>
27+
-----
28+
<?php
29+
30+
namespace test\PhpStaticAnalysis\RectorRule\Fixture;
31+
32+
use Exception;
33+
34+
/**
35+
* @deprecated
36+
*/
37+
#[\PhpStaticAnalysis\Attributes\Template('T')]
38+
class ExcludeAnnotationsTest
39+
{
40+
#[\PhpStaticAnalysis\Attributes\Type('string')]
41+
public $name;
42+
43+
/**
44+
* @throws Exception
45+
*/
46+
public function throwsException()
47+
{
48+
}
49+
}
50+
51+
?>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector;
6+
use PhpStaticAnalysis\RectorRule\Set\PhpStaticAnalysisSetList;
7+
use Rector\Config\RectorConfig;
8+
9+
return static function (RectorConfig $rectorConfig): void {
10+
$rectorConfig->sets([
11+
PhpStaticAnalysisSetList::ANNOTATIONS_TO_ATTRIBUTES
12+
]);
13+
$rectorConfig->ruleWithConfiguration(
14+
AnnotationsToAttributesRector::class,
15+
[
16+
'excludeAnnotations' => ['throws', 'deprecated'],
17+
]
18+
);
19+
};

0 commit comments

Comments
 (0)