Skip to content

Commit 610bc6e

Browse files
committed
Support all attribute targets
This adds support for properties, class constants, params, enums
1 parent 67ea78d commit 610bc6e

File tree

8 files changed

+247
-8
lines changed

8 files changed

+247
-8
lines changed

.github/workflows/php.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929
run: composer lint
3030
- php-version: "8.0"
3131
run: composer lint
32+
- php-version: "8.1"
33+
run: composer lint
3234
include:
3335
- php-version: "7.2"
3436
run: composer lint-7.x
@@ -38,6 +40,8 @@ jobs:
3840
run: composer lint-7.x
3941
- php-version: "8.0"
4042
run: composer lint-8.0
43+
- php-version: "8.1"
44+
run: composer lint-8.1
4145

4246
steps:
4347
- uses: actions/checkout@v4

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@
4141
},
4242
"scripts": {
4343
"lint": "vendor/bin/parallel-lint --colors src/ tests/",
44-
"lint-7.x": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/TypesEverywhere.php --exclude tests/src/disallowed/functionCallsNamedParams.php --exclude tests/src/disallowed-allow/functionCallsNamedParams.php --exclude tests/src/disallowed/attributeUsages.php --exclude tests/src/disallowed-allow/attributeUsages.php",
45-
"lint-8.0": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/TypesEverywhere.php",
44+
"lint-7.x": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/TypesEverywhere.php --exclude tests/src/AttributesEverywhere.php --exclude tests/src/disallowed/functionCallsNamedParams.php --exclude tests/src/disallowed-allow/functionCallsNamedParams.php --exclude tests/src/disallowed/attributeUsages.php --exclude tests/src/disallowed-allow/attributeUsages.php",
45+
"lint-8.0": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/TypesEverywhere.php --exclude tests/src/AttributesEverywhere.php",
46+
"lint-8.1": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/AttributesEverywhere.php",
4647
"lint-neon": "vendor/bin/neon-lint .",
4748
"phpcs": "vendor/bin/phpcs src/ tests/",
4849
"cs-fix": "vendor/bin/phpcbf src/ tests/",

src/Usages/AttributeUsages.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
use PhpParser\Node\Attribute;
88
use PhpParser\Node\AttributeGroup;
99
use PhpParser\Node\FunctionLike;
10+
use PhpParser\Node\Param;
11+
use PhpParser\Node\Stmt\ClassConst;
1012
use PhpParser\Node\Stmt\ClassLike;
13+
use PhpParser\Node\Stmt\EnumCase;
14+
use PhpParser\Node\Stmt\Property;
1115
use PHPStan\Analyser\Scope;
1216
use PHPStan\Rules\Rule;
1317
use Spaze\PHPStan\Rules\Disallowed\DisallowedAttribute;
@@ -72,6 +76,14 @@ public function processNode(Node $node, Scope $scope): array
7276
$this->addAttrs(array_values($node->attrGroups));
7377
} elseif ($node instanceof FunctionLike) {
7478
$this->addAttrs(array_values($node->getAttrGroups()));
79+
} elseif ($node instanceof Property) {
80+
$this->addAttrs(array_values($node->attrGroups));
81+
} elseif ($node instanceof ClassConst) {
82+
$this->addAttrs(array_values($node->attrGroups));
83+
} elseif ($node instanceof Param) {
84+
$this->addAttrs(array_values($node->attrGroups));
85+
} elseif ($node instanceof EnumCase) {
86+
$this->addAttrs(array_values($node->attrGroups));
7587
} else {
7688
return [];
7789
}

tests/Usages/AttributeUsagesAllowParamsMultipleTest.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,25 @@ public function testRule(): void
7171
// on this line:
7272
8,
7373
],
74+
[
75+
'Attribute Attributes\AttributeEntity is forbidden.',
76+
12,
77+
],
78+
[
79+
'Attribute Attributes\AttributeEntity is forbidden.',
80+
15,
81+
],
82+
[
83+
'Attribute Attributes\AttributeEntity is forbidden.',
84+
18,
85+
],
7486
[
7587
'Attribute Attributes\AttributeClass is forbidden.',
76-
30,
88+
40,
89+
],
90+
[
91+
'Attribute Attributes\AttributeEntity is forbidden.',
92+
42,
7793
],
7894
]);
7995
$this->analyse([__DIR__ . '/../src/disallowed-allow/ClassWithAttributesAllow.php'], [
@@ -85,10 +101,26 @@ public function testRule(): void
85101
'Attribute Attributes\AttributeEntity is forbidden.',
86102
12,
87103
],
104+
[
105+
'Attribute Attributes\AttributeEntity is forbidden.',
106+
15,
107+
],
88108
[
89109
'Attribute Attributes\AttributeEntity is forbidden.',
90110
18,
91111
],
112+
[
113+
'Attribute Attributes\AttributeEntity is forbidden.',
114+
22,
115+
],
116+
[
117+
'Attribute Attributes\AttributeEntity is forbidden.',
118+
28,
119+
],
120+
[
121+
'Attribute Attributes\AttributeEntity is forbidden.',
122+
42,
123+
],
92124
]);
93125
}
94126

tests/Usages/AttributeUsagesTest.php

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,99 @@ public function testRule(): void
6363
// on this line:
6464
8,
6565
],
66+
[
67+
'Attribute Attributes\AttributeEntity is forbidden.',
68+
12,
69+
],
70+
[
71+
'Attribute Attributes\AttributeEntity is forbidden.',
72+
15,
73+
],
74+
[
75+
'Attribute Attributes\AttributeEntity is forbidden.',
76+
18,
77+
],
6678
[
6779
'Attribute Attributes\AttributeClass is forbidden.',
68-
30,
80+
40,
81+
],
82+
[
83+
'Attribute Attributes\AttributeEntity is forbidden.',
84+
42,
6985
],
7086
]);
7187
$this->analyse([__DIR__ . '/../src/disallowed-allow/ClassWithAttributesAllow.php'], []);
88+
89+
$this->analyse([__DIR__ . '/../src/AttributesEverywhere.php'], [
90+
[
91+
'Attribute Attributes\AttributeClass is forbidden.',
92+
6,
93+
],
94+
[
95+
'Attribute Attributes\AttributeClass is forbidden.',
96+
10,
97+
],
98+
[
99+
'Attribute Attributes\AttributeClass is forbidden.',
100+
13,
101+
],
102+
[
103+
'Attribute Attributes\AttributeClass is forbidden.',
104+
19,
105+
],
106+
[
107+
'Attribute Attributes\AttributeClass is forbidden.',
108+
23,
109+
],
110+
[
111+
'Attribute Attributes\AttributeClass is forbidden.',
112+
26,
113+
],
114+
[
115+
'Attribute Attributes\AttributeClass is forbidden.',
116+
30,
117+
],
118+
[
119+
'Attribute Attributes\AttributeClass is forbidden.',
120+
32,
121+
],
122+
[
123+
'Attribute Attributes\AttributeClass is forbidden.',
124+
48,
125+
],
126+
[
127+
'Attribute Attributes\AttributeClass is forbidden.',
128+
52,
129+
],
130+
[
131+
'Attribute Attributes\AttributeClass is forbidden.',
132+
54,
133+
],
134+
[
135+
'Attribute Attributes\AttributeClass is forbidden.',
136+
61,
137+
],
138+
[
139+
'Attribute Attributes\AttributeClass is forbidden.',
140+
63,
141+
],
142+
[
143+
'Attribute Attributes\AttributeClass is forbidden.',
144+
69,
145+
],
146+
[
147+
'Attribute Attributes\AttributeClass is forbidden.',
148+
70,
149+
],
150+
[
151+
'Attribute Attributes\AttributeClass is forbidden.',
152+
76,
153+
],
154+
[
155+
'Attribute Attributes\AttributeClass is forbidden.',
156+
77,
157+
],
158+
]);
72159
}
73160

74161
}

tests/src/AttributesEverywhere.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
declare(strict_types = 1);
3+
4+
namespace Attributes;
5+
6+
#[AttributeClass]
7+
enum EnumWithAttributes
8+
{
9+
10+
#[AttributeClass]
11+
public const ENUM_CONST = true;
12+
13+
#[AttributeClass]
14+
case Foo;
15+
16+
}
17+
18+
19+
#[AttributeClass]
20+
trait TraitWithAttributes
21+
{
22+
23+
#[AttributeClass]
24+
private const TRAIT_CONST = true;
25+
26+
#[AttributeClass]
27+
private $bar;
28+
29+
30+
#[AttributeClass]
31+
public function traitMethod(
32+
#[AttributeClass]
33+
bool $param
34+
): void {
35+
}
36+
37+
}
38+
39+
// https://phpstan.org/blog/how-phpstan-analyses-traits
40+
class ClassWithTraitWithAttributes
41+
{
42+
43+
use TraitWithAttributes;
44+
45+
}
46+
47+
48+
#[AttributeClass]
49+
interface InterfaceWithAttributes
50+
{
51+
52+
#[AttributeClass]
53+
public function interfaceMethod(
54+
#[AttributeClass]
55+
bool $param
56+
): void;
57+
58+
}
59+
60+
61+
#[AttributeClass]
62+
function functionWithAttributes(
63+
#[AttributeClass]
64+
int $param
65+
): void {
66+
}
67+
68+
69+
$anonymousFunction = #[AttributeClass] function (
70+
#[AttributeClass]
71+
int $param
72+
): void {
73+
};
74+
75+
76+
$arrowFunction = #[AttributeClass] fn(
77+
#[AttributeClass]
78+
int $param
79+
) => 1;

tests/src/disallowed-allow/ClassWithAttributesAllow.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
class ClassWithAttributesAllow
1010
{
1111

12+
#[AttributeEntity] // allowed by path in all tests
13+
private const MAYO = true;
14+
15+
#[AttributeEntity] // allowed by path in all tests
16+
public $cheddar = 'plz';
17+
18+
#[AttributeEntity] // disallowed
19+
public static $pepper = 'ofc';
20+
21+
1222
#[\Attributes\AttributeEntity(repositoryClass: \Attributes\UserRepository::class, readOnly: false)] // allowed by path in AttributeUsagesTest, disallowed in AttributeUsagesAllowParamsMultipleTest because $repositoryClass has other value
1323
public function hasAvocado(): bool
1424
{
@@ -28,8 +38,10 @@ public function hasKetchup(): bool
2838

2939

3040
#[AttributeClass()] // allowed by path in all tests
31-
public function hasPineapple(): bool
32-
{
41+
public function hasPineapple(
42+
#[AttributeEntity] // allowed by path in all tests
43+
bool $really
44+
): bool {
3345
}
3446

3547
}

tests/src/disallowed/ClassWithAttributes.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
class ClassWithAttributes
1010
{
1111

12+
#[AttributeEntity] // disallowed
13+
private const MAYO = true;
14+
15+
#[AttributeEntity] // disallowed
16+
public $cheddar = 'plz';
17+
18+
#[AttributeEntity] // disallowed
19+
public static $pepper = 'ofc';
20+
21+
1222
#[AttributeEntity(repositoryClass: UserRepository::class, readOnly: false)] // disallowed, $repositoryClass present with any value
1323
public function hasAvocado(): bool
1424
{
@@ -28,8 +38,10 @@ public function hasKetchup(): bool
2838

2939

3040
#[AttributeClass()] // disallowed
31-
public function hasPineapple(): bool
32-
{
41+
public function hasPineapple(
42+
#[AttributeEntity] // disallowed
43+
bool $really
44+
): bool {
3345
}
3446

3547
}

0 commit comments

Comments
 (0)