From 1d205456f85ab627d1ec06c4d80129d8bd8e2ec0 Mon Sep 17 00:00:00 2001 From: raalderink Date: Tue, 18 Apr 2023 15:32:03 +0200 Subject: [PATCH] Add extension to add additional constructors through code --- .../AdditionalConstructorsExtension.php | 29 +++++++++++++++++++ src/Reflection/ConstructorsHelper.php | 11 +++++++ ...ReadOnlyByPhpDocPropertyAssignRuleTest.php | 9 ++++-- .../MissingReadOnlyPropertyAssignRuleTest.php | 9 ++++-- ...ReadOnlyByPhpDocPropertyAssignRuleTest.php | 1 + .../ReadOnlyPropertyAssignRuleTest.php | 1 + .../UninitializedPropertyRuleTest.php | 22 ++++++++++++++ ...opertyAdditionalConstructorsExtensions.php | 20 +++++++++++++ ...lized-property-additional-constructors.php | 22 ++++++++++++++ .../uninitialized-property-rule.neon | 5 ++++ 10 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 src/Reflection/AdditionalConstructorsExtension.php create mode 100644 tests/PHPStan/Rules/Properties/data/UninitializedPropertyAdditionalConstructorsExtensions.php create mode 100644 tests/PHPStan/Rules/Properties/data/uninitialized-property-additional-constructors.php create mode 100644 tests/PHPStan/Rules/Properties/uninitialized-property-rule.neon diff --git a/src/Reflection/AdditionalConstructorsExtension.php b/src/Reflection/AdditionalConstructorsExtension.php new file mode 100644 index 0000000000..ad9995b64c --- /dev/null +++ b/src/Reflection/AdditionalConstructorsExtension.php @@ -0,0 +1,29 @@ + $additionalConstructors */ public function __construct( + private Container $container, private array $additionalConstructors, ) { @@ -34,6 +36,15 @@ public function getConstructors(ClassReflection $classReflection): array $constructors[] = $classReflection->getConstructor()->getName(); } + /** @var AdditionalConstructorsExtension[] $extensions */ + $extensions = $this->container->getServicesByTag(AdditionalConstructorsExtension::EXTENSION_TAG); + foreach ($extensions as $extension) { + $extensionConstructors = $extension->getAdditionalConstructors($classReflection); + foreach ($extensionConstructors as $extensionConstructor) { + $constructors[] = $extensionConstructor; + } + } + $nativeReflection = $classReflection->getNativeReflection(); foreach ($this->additionalConstructors as $additionalConstructor) { [$className, $methodName] = explode('::', $additionalConstructor); diff --git a/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php index 30f3872c84..0177b6ab36 100644 --- a/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php @@ -18,9 +18,12 @@ class MissingReadOnlyByPhpDocPropertyAssignRuleTest extends RuleTestCase protected function getRule(): Rule { return new MissingReadOnlyByPhpDocPropertyAssignRule( - new ConstructorsHelper([ - 'MissingReadOnlyPropertyAssignPhpDoc\\TestCase::setUp', - ]), + new ConstructorsHelper( + self::getContainer(), + [ + 'MissingReadOnlyPropertyAssignPhpDoc\\TestCase::setUp', + ], + ), ); } diff --git a/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php index 638e9d74b4..fc67094134 100644 --- a/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php @@ -18,9 +18,12 @@ class MissingReadOnlyPropertyAssignRuleTest extends RuleTestCase protected function getRule(): Rule { return new MissingReadOnlyPropertyAssignRule( - new ConstructorsHelper([ - 'MissingReadOnlyPropertyAssign\\TestCase::setUp', - ]), + new ConstructorsHelper( + self::getContainer(), + [ + 'MissingReadOnlyPropertyAssign\\TestCase::setUp', + ], + ), ); } diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php index bac6bace61..197473fbf5 100644 --- a/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyAssignRuleTest.php @@ -18,6 +18,7 @@ protected function getRule(): Rule return new ReadOnlyByPhpDocPropertyAssignRule( new PropertyReflectionFinder(), new ConstructorsHelper( + self::getContainer(), [ 'ReadonlyPropertyAssignPhpDoc\\TestCase::setUp', ], diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php index 2cab38f8d2..fec1fb1192 100644 --- a/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadOnlyPropertyAssignRuleTest.php @@ -18,6 +18,7 @@ protected function getRule(): Rule return new ReadOnlyPropertyAssignRule( new PropertyReflectionFinder(), new ConstructorsHelper( + self::getContainer(), [ 'ReadonlyPropertyAssign\\TestCase::setUp', ], diff --git a/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php b/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php index 7273e07695..a0bc9e31e1 100644 --- a/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php +++ b/tests/PHPStan/Rules/Properties/UninitializedPropertyRuleTest.php @@ -17,6 +17,7 @@ protected function getRule(): Rule { return new UninitializedPropertyRule( new ConstructorsHelper( + self::getContainer(), [ 'UninitializedProperty\\TestCase::setUp', ], @@ -48,6 +49,13 @@ public function isInitialized(PropertyReflection $property, string $propertyName ]; } + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/uninitialized-property-rule.neon', + ]; + } + public function testRule(): void { $this->analyse([__DIR__ . '/data/uninitialized-property.php'], [ @@ -113,4 +121,18 @@ public function testBug7219(): void ]); } + public function testAdditionalConstructorsExtension(): void + { + $this->analyse([__DIR__ . '/data/uninitialized-property-additional-constructors.php'], [ + [ + 'Class TestInitializedProperty\TestAdditionalConstructor has an uninitialized property $one. Give it default value or assign it in the constructor.', + 07, + ], + [ + 'Class TestInitializedProperty\TestAdditionalConstructor has an uninitialized property $three. Give it default value or assign it in the constructor.', + 11, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/UninitializedPropertyAdditionalConstructorsExtensions.php b/tests/PHPStan/Rules/Properties/data/UninitializedPropertyAdditionalConstructorsExtensions.php new file mode 100644 index 0000000000..316a4e136e --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/UninitializedPropertyAdditionalConstructorsExtensions.php @@ -0,0 +1,20 @@ +getName() === 'TestInitializedProperty\\TestAdditionalConstructor') { + return ['setTwo']; + } + + return []; + } + +} diff --git a/tests/PHPStan/Rules/Properties/data/uninitialized-property-additional-constructors.php b/tests/PHPStan/Rules/Properties/data/uninitialized-property-additional-constructors.php new file mode 100644 index 0000000000..7e3cda91a5 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/uninitialized-property-additional-constructors.php @@ -0,0 +1,22 @@ += 7.4 + +namespace TestInitializedProperty; + +class TestAdditionalConstructor +{ + public string $one; + + protected int $two; + + protected int $three; + + public function setTwo(int $value): void + { + $this->two = $value; + } + + public function setThree(int $value): void + { + $this->three = $value; + } +} diff --git a/tests/PHPStan/Rules/Properties/uninitialized-property-rule.neon b/tests/PHPStan/Rules/Properties/uninitialized-property-rule.neon new file mode 100644 index 0000000000..6362843ec8 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/uninitialized-property-rule.neon @@ -0,0 +1,5 @@ +services: + - + class: PHPStan\Rules\Properties\TestInitializedProperty + tags: + - phpstan.additionalConstructorsExtension