From d8023eea1c5f6aa6a8c71c816b96b96769a9966b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Wed, 6 Dec 2023 03:06:59 +0100 Subject: [PATCH] Support all attribute targets This adds support for properties, class constants, params, enums Close #224 --- .github/workflows/php.yml | 4 + composer.json | 5 +- src/Usages/AttributeUsages.php | 12 +++ ...AttributeUsagesAllowParamsMultipleTest.php | 34 ++++++- tests/Usages/AttributeUsagesTest.php | 89 ++++++++++++++++++- tests/src/AttributesEverywhere.php | 79 ++++++++++++++++ .../ClassWithAttributesAllow.php | 16 +++- tests/src/disallowed/ClassWithAttributes.php | 16 +++- 8 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 tests/src/AttributesEverywhere.php diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 95a384b..89e5ebb 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -29,6 +29,8 @@ jobs: run: composer lint - php-version: "8.0" run: composer lint + - php-version: "8.1" + run: composer lint include: - php-version: "7.2" run: composer lint-7.x @@ -38,6 +40,8 @@ jobs: run: composer lint-7.x - php-version: "8.0" run: composer lint-8.0 + - php-version: "8.1" + run: composer lint-8.1 steps: - uses: actions/checkout@v4 diff --git a/composer.json b/composer.json index 1d08229..56a8f6d 100644 --- a/composer.json +++ b/composer.json @@ -41,8 +41,9 @@ }, "scripts": { "lint": "vendor/bin/parallel-lint --colors src/ tests/", - "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", - "lint-8.0": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/TypesEverywhere.php", + "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", + "lint-8.0": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/TypesEverywhere.php --exclude tests/src/AttributesEverywhere.php", + "lint-8.1": "vendor/bin/parallel-lint --colors src/ tests/ --exclude tests/src/AttributesEverywhere.php", "lint-neon": "vendor/bin/neon-lint .", "phpcs": "vendor/bin/phpcs src/ tests/", "cs-fix": "vendor/bin/phpcbf src/ tests/", diff --git a/src/Usages/AttributeUsages.php b/src/Usages/AttributeUsages.php index 4515c60..7a594e0 100644 --- a/src/Usages/AttributeUsages.php +++ b/src/Usages/AttributeUsages.php @@ -7,7 +7,11 @@ use PhpParser\Node\Attribute; use PhpParser\Node\AttributeGroup; use PhpParser\Node\FunctionLike; +use PhpParser\Node\Param; +use PhpParser\Node\Stmt\ClassConst; use PhpParser\Node\Stmt\ClassLike; +use PhpParser\Node\Stmt\EnumCase; +use PhpParser\Node\Stmt\Property; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use Spaze\PHPStan\Rules\Disallowed\DisallowedAttribute; @@ -72,6 +76,14 @@ public function processNode(Node $node, Scope $scope): array $this->addAttrs(array_values($node->attrGroups)); } elseif ($node instanceof FunctionLike) { $this->addAttrs(array_values($node->getAttrGroups())); + } elseif ($node instanceof Property) { + $this->addAttrs(array_values($node->attrGroups)); + } elseif ($node instanceof ClassConst) { + $this->addAttrs(array_values($node->attrGroups)); + } elseif ($node instanceof Param) { + $this->addAttrs(array_values($node->attrGroups)); + } elseif ($node instanceof EnumCase) { + $this->addAttrs(array_values($node->attrGroups)); } else { return []; } diff --git a/tests/Usages/AttributeUsagesAllowParamsMultipleTest.php b/tests/Usages/AttributeUsagesAllowParamsMultipleTest.php index 7a4a4f1..0539bca 100644 --- a/tests/Usages/AttributeUsagesAllowParamsMultipleTest.php +++ b/tests/Usages/AttributeUsagesAllowParamsMultipleTest.php @@ -71,9 +71,25 @@ public function testRule(): void // on this line: 8, ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 12, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 15, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 18, + ], [ 'Attribute Attributes\AttributeClass is forbidden.', - 30, + 40, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 42, ], ]); $this->analyse([__DIR__ . '/../src/disallowed-allow/ClassWithAttributesAllow.php'], [ @@ -85,10 +101,26 @@ public function testRule(): void 'Attribute Attributes\AttributeEntity is forbidden.', 12, ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 15, + ], [ 'Attribute Attributes\AttributeEntity is forbidden.', 18, ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 22, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 28, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 42, + ], ]); } diff --git a/tests/Usages/AttributeUsagesTest.php b/tests/Usages/AttributeUsagesTest.php index af25218..55769c9 100644 --- a/tests/Usages/AttributeUsagesTest.php +++ b/tests/Usages/AttributeUsagesTest.php @@ -63,12 +63,99 @@ public function testRule(): void // on this line: 8, ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 12, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 15, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 18, + ], [ 'Attribute Attributes\AttributeClass is forbidden.', - 30, + 40, + ], + [ + 'Attribute Attributes\AttributeEntity is forbidden.', + 42, ], ]); $this->analyse([__DIR__ . '/../src/disallowed-allow/ClassWithAttributesAllow.php'], []); + + $this->analyse([__DIR__ . '/../src/AttributesEverywhere.php'], [ + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 6, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 10, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 13, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 19, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 23, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 26, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 30, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 32, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 48, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 52, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 54, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 61, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 63, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 69, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 70, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 76, + ], + [ + 'Attribute Attributes\AttributeClass is forbidden.', + 77, + ], + ]); } } diff --git a/tests/src/AttributesEverywhere.php b/tests/src/AttributesEverywhere.php new file mode 100644 index 0000000..efa52ee --- /dev/null +++ b/tests/src/AttributesEverywhere.php @@ -0,0 +1,79 @@ + 1; diff --git a/tests/src/disallowed-allow/ClassWithAttributesAllow.php b/tests/src/disallowed-allow/ClassWithAttributesAllow.php index 3b3384a..dedde20 100644 --- a/tests/src/disallowed-allow/ClassWithAttributesAllow.php +++ b/tests/src/disallowed-allow/ClassWithAttributesAllow.php @@ -9,6 +9,16 @@ class ClassWithAttributesAllow { + #[AttributeEntity] // allowed by path in all tests + private const MAYO = true; + + #[AttributeEntity] // allowed by path in all tests + public $cheddar = 'plz'; + + #[AttributeEntity] // disallowed + public static $pepper = 'ofc'; + + #[\Attributes\AttributeEntity(repositoryClass: \Attributes\UserRepository::class, readOnly: false)] // allowed by path in AttributeUsagesTest, disallowed in AttributeUsagesAllowParamsMultipleTest because $repositoryClass has other value public function hasAvocado(): bool { @@ -28,8 +38,10 @@ public function hasKetchup(): bool #[AttributeClass()] // allowed by path in all tests - public function hasPineapple(): bool - { + public function hasPineapple( + #[AttributeEntity] // allowed by path in all tests + bool $really + ): bool { } } diff --git a/tests/src/disallowed/ClassWithAttributes.php b/tests/src/disallowed/ClassWithAttributes.php index 6abc5de..0b87416 100644 --- a/tests/src/disallowed/ClassWithAttributes.php +++ b/tests/src/disallowed/ClassWithAttributes.php @@ -9,6 +9,16 @@ class ClassWithAttributes { + #[AttributeEntity] // disallowed + private const MAYO = true; + + #[AttributeEntity] // disallowed + public $cheddar = 'plz'; + + #[AttributeEntity] // disallowed + public static $pepper = 'ofc'; + + #[AttributeEntity(repositoryClass: UserRepository::class, readOnly: false)] // disallowed, $repositoryClass present with any value public function hasAvocado(): bool { @@ -28,8 +38,10 @@ public function hasKetchup(): bool #[AttributeClass()] // disallowed - public function hasPineapple(): bool - { + public function hasPineapple( + #[AttributeEntity] // disallowed + bool $really + ): bool { } }