diff --git a/src/Rule/EnforceReadonlyPublicPropertyRule.php b/src/Rule/EnforceReadonlyPublicPropertyRule.php index 7d74463..6804eef 100644 --- a/src/Rule/EnforceReadonlyPublicPropertyRule.php +++ b/src/Rule/EnforceReadonlyPublicPropertyRule.php @@ -2,6 +2,7 @@ namespace ShipMonk\PHPStan\Rule; +use LogicException; use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\ClassPropertyNode; @@ -9,6 +10,8 @@ use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; +use ReflectionException; +use function strpos; /** * @implements Rule @@ -48,6 +51,24 @@ public function processNode(Node $node, Scope $scope): array return []; } + try { + $propertyReflection = $node->getClassReflection()->getNativeReflection()->getProperty($node->getName()); + } catch (ReflectionException $e) { + throw new LogicException('Property isn\'t found in class reflection.', 0, $e); + } + + $attributeName = 'Nette\\DI\\Attributes\\Inject'; + + if ($propertyReflection->getAttributes($attributeName) !== []) { // @phpstan-ignore argument.type + return []; + } + + $phpdoc = $propertyReflection->getDocComment(); + + if ($phpdoc !== false && strpos($phpdoc, '@inject') !== false) { + return []; + } + $error = RuleErrorBuilder::message("Public property `{$node->getName()}` not marked as readonly.") ->identifier('shipmonk.publicPropertyNotReadonly') ->build(); diff --git a/tests/Rule/EnforceReadonlyPublicPropertyRuleTest.php b/tests/Rule/EnforceReadonlyPublicPropertyRuleTest.php index 3ae718b..333c0ad 100644 --- a/tests/Rule/EnforceReadonlyPublicPropertyRuleTest.php +++ b/tests/Rule/EnforceReadonlyPublicPropertyRuleTest.php @@ -43,6 +43,12 @@ public function testPhp80(): void $this->analyseFile(__DIR__ . '/data/EnforceReadonlyPublicPropertyRule/code-80.php'); } + public function testNetteInject(): void + { + $this->phpVersion = $this->createPhpVersion(80_100); + $this->analyseFile(__DIR__ . '/data/EnforceReadonlyPublicPropertyRule/code-nette-inject.php'); + } + private function createPhpVersion(int $version): PhpVersion { return new PhpVersion($version); // @phpstan-ignore phpstanApi.constructor diff --git a/tests/Rule/data/EnforceReadonlyPublicPropertyRule/code-nette-inject.php b/tests/Rule/data/EnforceReadonlyPublicPropertyRule/code-nette-inject.php new file mode 100644 index 0000000..2037f24 --- /dev/null +++ b/tests/Rule/data/EnforceReadonlyPublicPropertyRule/code-nette-inject.php @@ -0,0 +1,23 @@ +