1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Support property type promotion ref #4089

This commit is contained in:
Matt Brown 2020-10-02 18:31:32 -04:00 committed by Daniil Gentili
parent 7d5e9ef5f3
commit 613ce96582
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
2 changed files with 101 additions and 0 deletions

View File

@ -1854,6 +1854,8 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$fq_classlike_name = null; $fq_classlike_name = null;
$is_functionlike_override = false; $is_functionlike_override = false;
$method_name_lc = null;
if ($fake_method && $stmt instanceof PhpParser\Node\Stmt\ClassMethod) { if ($fake_method && $stmt instanceof PhpParser\Node\Stmt\ClassMethod) {
$cased_function_id = '@method ' . $stmt->name->name; $cased_function_id = '@method ' . $stmt->name->name;
@ -2359,6 +2361,61 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
} }
} }
if ($class_storage && $method_name_lc === '__construct') {
foreach ($stmt->getParams() as $param) {
if (!$param->flags || !$param->var instanceof PhpParser\Node\Expr\Variable) {
continue;
}
$param_storage = null;
foreach ($storage->params as $param_storage) {
if ($param_storage->name === $param->var->name) {
break;
}
}
if (!$param_storage) {
continue;
}
$property_storage = $class_storage->properties[$param_storage->name] = new PropertyStorage();
$property_storage->is_static = false;
$property_storage->type = $param_storage->type;
$property_storage->signature_type = $param_storage->signature_type;
$property_storage->signature_type_location = $param_storage->signature_type_location;
$property_storage->type_location = $param_storage->type_location;
$property_storage->location = $param_storage->location;
$property_storage->stmt_location = new CodeLocation($this->file_scanner, $param);
$property_storage->has_default = $param->default ? true : false;
$property_id = $fq_classlike_name . '::$' . $param_storage->name;
switch ($param->flags) {
case \PhpParser\Node\Stmt\Class_::MODIFIER_PUBLIC:
$property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC;
$class_storage->inheritable_property_ids[$param_storage->name] = $property_id;
break;
case \PhpParser\Node\Stmt\Class_::MODIFIER_PROTECTED:
$property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PROTECTED;
$class_storage->inheritable_property_ids[$param_storage->name] = $property_id;
break;
case \PhpParser\Node\Stmt\Class_::MODIFIER_PRIVATE:
$property_storage->visibility = ClassLikeAnalyzer::VISIBILITY_PRIVATE;
break;
}
$fq_classlike_name = $this->fq_classlike_names[count($this->fq_classlike_names) - 1];
$property_id = $fq_classlike_name . '::$' . $param_storage->name;
$class_storage->declaring_property_ids[$param_storage->name] = $fq_classlike_name;
$class_storage->appearing_property_ids[$param_storage->name] = $property_id;
}
}
if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod
&& $stmt->name->name === '__construct' && $stmt->name->name === '__construct'
&& $class_storage && $class_storage

View File

@ -2074,6 +2074,34 @@ class PropertyTypeTest extends TestCase
} }
}' }'
], ],
'promotedPublicProperty' => [
'<?php
class A {
public function __construct(public int $foo = 5) {}
}
echo (new A)->foo;'
],
'promotedProtectedProperty' => [
'<?php
class A {
public function __construct(protected int $foo = 5) {}
}
class AChild extends A {
public function bar() : int {
return $this->foo;
}
}'
],
'setPublicProperty' => [
'<?php
class A {
public function __construct(public int $foo) {
$this->foo = 5;
}
}'
],
]; ];
} }
@ -3214,6 +3242,22 @@ class PropertyTypeTest extends TestCase
}', }',
'error_message' => 'MissingPropertyType', 'error_message' => 'MissingPropertyType',
], ],
'promotedPrivateProperty' => [
'<?php
class A {
public function __construct(private int $foo = 5) {}
}
echo (new A)->foo;',
'error_message' => 'InaccessibleProperty',
],
'promotedPublicPropertyWithoutSet' => [
'<?php
class A {
public function __construct(public int $foo) {}
}',
'error_message' => 'PropertyNotSetInConstructor'
],
]; ];
} }
} }