Skip to content

Commit

Permalink
Add @readonly rule that disallows default values
Browse files Browse the repository at this point in the history
  • Loading branch information
herndlm committed Jun 6, 2022
1 parent 3a7a22d commit 04b22f9
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
5 changes: 5 additions & 0 deletions conf/config.level0.neon
Expand Up @@ -6,6 +6,8 @@ conditionalTags:
phpstan.rules.rule: %featureToggles.nodeConnectingVisitorRule%
PHPStan\Rules\Properties\MissingReadOnlyByPhpDocPropertyAssignRule:
phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc%
PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyRule:
phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc%
PHPStan\Rules\Properties\UninitializedPropertyRule:
phpstan.rules.rule: %checkUninitializedProperties%
PHPStan\Rules\Methods\ConsistentConstructorRule:
Expand Down Expand Up @@ -188,6 +190,9 @@ services:
tags:
- phpstan.rules.rule

-
class: PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyRule

-
class: PHPStan\Rules\Properties\UninitializedPropertyRule

Expand Down
36 changes: 36 additions & 0 deletions src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Properties;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\ClassPropertyNode;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

/**
* @implements Rule<ClassPropertyNode>
*/
class ReadOnlyByPhpDocPropertyRule implements Rule
{

public function getNodeType(): string
{
return ClassPropertyNode::class;
}

public function processNode(Node $node, Scope $scope): array
{
if (!$node->isReadOnlyByPhpDoc()) {
return [];
}

$errors = [];
if ($node->getDefault() !== null) {
$errors[] = RuleErrorBuilder::message('@readonly property cannot have a default value.')->build();
}

return $errors;
}

}
@@ -0,0 +1,34 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Properties;

use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use const PHP_VERSION_ID;

/**
* @extends RuleTestCase<ReadOnlyByPhpDocPropertyRule>
*/
class ReadOnlyByPhpDocPropertyRuleTest extends RuleTestCase
{

protected function getRule(): Rule
{
return new ReadOnlyByPhpDocPropertyRule();
}

public function testRule(): void
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Test requires PHP 8.1.');
}

$this->analyse([__DIR__ . '/data/read-only-property-phpdoc.php'], [
[
'@readonly property cannot have a default value.',
21,
],
]);
}

}
33 changes: 33 additions & 0 deletions tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php
@@ -0,0 +1,33 @@
<?php // lint >= 8.1

namespace ReadOnlyPropertyPhpDoc;

class Foo
{

/**
* @readonly
* @var int
*/
private $foo;

/** @readonly */
private $bar;

/**
* @readonly
* @var int
*/
private $baz = 0;

}

final class ErrorResponse
{
public function __construct(
/** @readonly */
public string $message = ''
)
{
}
}

0 comments on commit 04b22f9

Please sign in to comment.