1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 12:24:49 +01:00

Fix #1787 - prevent initialisation when nullable isn’t set

This commit is contained in:
Brown 2019-06-14 16:53:40 -04:00
parent edf3307f84
commit d1630863ad
4 changed files with 94 additions and 11 deletions

View File

@ -11,7 +11,7 @@
],
"require": {
"php": "^7.1",
"nikic/php-parser": "^4.0.2 || ^4.1",
"nikic/php-parser": "^4.2",
"openlss/lib-array2xml": "^1.0",
"ocramius/package-versions": "^1.2",
"composer/xdebug-handler": "^1.1",

View File

@ -657,7 +657,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
if (!$property_type->isMixed() &&
!$property_storage->has_default &&
!$property_type->isNullable()
!($property_type->isNullable() && $property_type->from_docblock)
) {
$property_type->initialized = false;
}
@ -1026,7 +1026,9 @@ class ClassAnalyzer extends ClassLikeAnalyzer
continue;
}
if ($property->type->isMixed() || $property->type->isNullable()) {
if ($property->type->isMixed()
|| ($property->type->isNullable() && $property->type->from_docblock)
) {
continue;
}
@ -1077,8 +1079,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
$constructor_storage = $constructor_class_storage->methods['__construct'];
$fake_constructor_params = array_map(
/** @return PhpParser\Node\Param */
function (FunctionLikeParameter $param) {
function (FunctionLikeParameter $param) : PhpParser\Node\Param {
$fake_param = (new PhpParser\Builder\Param($param->name));
if ($param->signature_type) {
/** @psalm-suppress DeprecatedMethod */
@ -1091,8 +1092,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
);
$fake_constructor_stmt_args = array_map(
/** @return PhpParser\Node\Arg */
function (FunctionLikeParameter $param) {
function (FunctionLikeParameter $param) : PhpParser\Node\Arg {
return new PhpParser\Node\Arg(new PhpParser\Node\Expr\Variable($param->name));
},
$constructor_storage->params

View File

@ -2729,12 +2729,11 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
$signature_type = null;
$signature_type_location = null;
/** @var null|PhpParser\Node\Identifier|PhpParser\Node\Name|PhpParser\Node\NullableType */
$parser_property_type = isset($stmt->type) ? $stmt->type : null;
if ($parser_property_type) {
if ($stmt->type) {
$suffix = '';
$parser_property_type = $stmt->type;
if ($parser_property_type instanceof PhpParser\Node\NullableType) {
$suffix = '|null';
$parser_property_type = $parser_property_type->type;

View File

@ -1609,6 +1609,33 @@ class PropertyTypeTest extends TestCase
}
}',
],
'nullableDocblockTypedPropertyNoConstructor' => [
'<?php
class A {
/** @var ?bool */
private $foo;
}',
],
'nullableDocblockTypedPropertyEmptyConstructor' => [
'<?php
class A {
/** @var ?bool */
private $foo;
public function __construct() {}
}',
],
'nullableDocblockTypedPropertyUseBeforeInitialised' => [
'<?php
class A {
/** @var ?bool */
private $foo;
public function __construct() {
echo $this->foo;
}
}',
],
];
}
@ -2460,6 +2487,63 @@ class PropertyTypeTest extends TestCase
}',
'error_message' => 'UndefinedInterfaceMethod'
],
'nullableTypedPropertyNoConstructor' => [
'<?php
class A {
private ?bool $foo;
}',
'error_message' => 'MissingConstructor'
],
'nullableTypedPropertyEmptyConstructor' => [
'<?php
class A {
private ?bool $foo;
public function __construct() {}
}',
'error_message' => 'PropertyNotSetInConstructor'
],
'nullableTypedPropertyUseBeforeInitialised' => [
'<?php
class A {
private ?bool $foo;
public function __construct() {
echo $this->foo;
}
}',
'error_message' => 'UninitializedProperty'
],
'nullableTypedPropertyNoConstructorWithDocblock' => [
'<?php
class A {
/** @var ?bool */
private ?bool $foo;
}',
'error_message' => 'MissingConstructor'
],
'nullableTypedPropertyEmptyConstructorWithDocblock' => [
'<?php
class A {
/** @var ?bool */
private ?bool $foo;
public function __construct() {}
}',
'error_message' => 'PropertyNotSetInConstructor'
],
'nullableTypedPropertyUseBeforeInitialisedWithDocblock' => [
'<?php
class A {
/** @var ?bool */
private ?bool $foo;
public function __construct() {
echo $this->foo;
}
}',
'error_message' => 'UninitializedProperty'
],
];
}
}