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:
parent
edf3307f84
commit
d1630863ad
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user