Skip to content
Permalink
Browse files

Add support for @readonly annotation

  • Loading branch information...
muglug committed Aug 11, 2019
1 parent 5722512 commit 7ed30cd5b0f6abe419a91131ab973be85d5bda0c
@@ -96,10 +96,6 @@ public static function arrayToDocblocks(
$comment_text = $comment->getText();
if (!isset($parsed_docblock['specials']['var']) && !isset($parsed_docblock['specials']['psalm-var'])) {
return [];
}
$var_line_number = $comment->getLine();
if ($parsed_docblock) {
@@ -184,6 +180,7 @@ public static function arrayToDocblocks(
$var_comment->type_end = $type_end;
$var_comment->deprecated = isset($parsed_docblock['specials']['deprecated']);
$var_comment->internal = isset($parsed_docblock['specials']['internal']);
$var_comment->readonly = isset($parsed_docblock['specials']['readonly']);
if (isset($parsed_docblock['specials']['psalm-internal'])) {
$psalm_internal = reset($parsed_docblock['specials']['psalm-internal']);
if ($psalm_internal) {
@@ -202,6 +199,19 @@ public static function arrayToDocblocks(
}
}
if (!$var_comments
&& (isset($parsed_docblock['specials']['deprecated'])
|| isset($parsed_docblock['specials']['internal'])
|| isset($parsed_docblock['specials']['readonly']))
) {
$var_comment = new VarDocblockComment();
$var_comment->deprecated = isset($parsed_docblock['specials']['deprecated']);
$var_comment->internal = isset($parsed_docblock['specials']['internal']);
$var_comment->readonly = isset($parsed_docblock['specials']['readonly']);
$var_comments[] = $var_comment;
}
return $var_comments;
}
@@ -14,6 +14,7 @@
use Psalm\Context;
use Psalm\Issue\DeprecatedProperty;
use Psalm\Issue\ImplicitToStringCast;
use Psalm\Issue\InaccessibleProperty;
use Psalm\Issue\InternalProperty;
use Psalm\Issue\InvalidPropertyAssignment;
use Psalm\Issue\InvalidPropertyAssignmentValue;
@@ -614,6 +615,32 @@ public static function analyzeInstance(
}
}
}
if ($property_storage->readonly) {
$appearing_property_class = $codebase->properties->getAppearingClassForProperty(
$property_id,
true
);
if ($appearing_property_class
&& !($context->self
&& ($appearing_property_class === $context->self
|| $codebase->classExtends($context->self, $appearing_property_class))
&& (!$context->calling_method_id
|| \strpos($context->calling_method_id, '::__construct'))
)
) {
if (IssueBuffer::accepts(
new InaccessibleProperty(
$property_id . ' is marked readonly',
new CodeLocation($statements_analyzer->getSource(), $stmt)
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
}
}
}
$class_property_type = $codebase->properties->getPropertyType(
@@ -58,4 +58,11 @@ class VarDocblockComment
* @var null|string
*/
public $psalm_internal = null;
/**
* Whether or not the property is readonly
*
* @var bool
*/
public $readonly = false;
}
@@ -2967,6 +2967,7 @@ private function visitPropertyDeclaration(
$property_storage->deprecated = $var_comment ? $var_comment->deprecated : false;
$property_storage->internal = $var_comment ? $var_comment->internal : false;
$property_storage->psalm_internal = $var_comment ? $var_comment->psalm_internal : null;
$property_storage->readonly = $var_comment ? $var_comment->readonly : false;
if (!$signature_type && !$doc_var_group_type) {
if ($property->default) {
@@ -69,6 +69,11 @@ class PropertyStorage
*/
public $internal = false;
/**
* @var bool
*/
public $readonly = false;
/**
* @var null|string
*/
@@ -1661,6 +1661,38 @@ public function __construct(Tag ...$tags) {
}
}',
],
'readonlyPropertySetInConstructor' => [
'<?php
class A {
/**
* @readonly
*/
public string $bar;
public function __construct() {
$this->bar = "hello";
}
}
echo (new A)->bar;'
],
'readonlyPropertySetChildClass' => [
'<?php
abstract class A {
/**
* @readonly
*/
public string $bar;
}
class B extends A {
public function __construct() {
$this->bar = "hello";
}
}
echo (new B)->bar;'
],
];
}
@@ -2592,6 +2624,61 @@ class TestStatic {
}',
'error_message' => 'InvalidPropertyAssignmentValue'
],
'readonlyPropertySetInConstructorAndAlsoAnotherMethodInsideClass' => [
'<?php
class A {
/**
* @readonly
*/
public string $bar;
public function __construct() {
$this->bar = "hello";
}
public function setBar() : void {
$this->bar = "goodbye";
}
}',
'error_message' => 'InaccessibleProperty',
],
'readonlyPropertySetInConstructorAndAlsoAnotherMethodInSublass' => [
'<?php
class A {
/**
* @readonly
*/
public string $bar;
public function __construct() {
$this->bar = "hello";
}
}
class B extends A {
public function setBar() : void {
$this->bar = "hello";
}
}',
'error_message' => 'InaccessibleProperty',
],
'readonlyPropertySetInConstructorAndAlsoOutsideClass' => [
'<?php
class A {
/**
* @readonly
*/
public string $bar;
public function __construct() {
$this->bar = "hello";
}
}
$a = new A();
$a->bar = "goodbye";',
'error_message' => 'InaccessibleProperty',
],
];
}
}

0 comments on commit 7ed30cd

Please sign in to comment.
You can’t perform that action at this time.