1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Add more robust property assignment when property not defined

This commit is contained in:
Matt Brown 2017-11-03 12:27:01 -04:00
parent a651fad6f0
commit 81493a639e
5 changed files with 14 additions and 33 deletions

View File

@ -127,7 +127,6 @@
<xs:element name="MissingClosureReturnType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingConstructor" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingFile" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingPropertyDeclaration" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingPropertyType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingReturnType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MixedArgument" type="IssueHandlerType" minOccurs="0" />

View File

@ -19,7 +19,6 @@ use Psalm\Issue\FailedTypeResolution;
use Psalm\Issue\InvalidArrayAssignment;
use Psalm\Issue\InvalidPropertyAssignment;
use Psalm\Issue\InvalidScope;
use Psalm\Issue\MissingPropertyDeclaration;
use Psalm\Issue\MixedAssignment;
use Psalm\Issue\MixedPropertyAssignment;
use Psalm\Issue\MixedStringOffsetAssignment;
@ -470,6 +469,8 @@ class AssignmentChecker
$project_checker = $statements_checker->getFileChecker()->project_checker;
$property_exists = false;
if ($stmt instanceof PropertyProperty) {
if (!$context->self || !$stmt->default) {
return null;
@ -481,6 +482,8 @@ class AssignmentChecker
return null;
}
$property_exists = true;
$declaring_property_class = ClassLikeChecker::getDeclaringClassForProperty($project_checker, $property_id);
$class_storage = $project_checker->classlike_storage_provider->get((string)$declaring_property_class);
@ -647,6 +650,7 @@ class AssignmentChecker
$class_property_types[] =
clone $class_storage->pseudo_property_set_types['$' . $prop_name];
$has_regular_setter = true;
$property_exists = true;
continue;
}
@ -672,10 +676,12 @@ class AssignmentChecker
$property_id = $lhs_type_part->value . '::$' . $prop_name;
if (!ClassLikeChecker::propertyExists($project_checker, $property_id)) {
$has_regular_setter = true;
if ($stmt->var instanceof PhpParser\Node\Expr\Variable && $stmt->var->name === 'this') {
// if this is a proper error, we'll see it on the first pass
if ($context->collect_mutations) {
return;
continue;
}
if (IssueBuffer::accepts(
@ -702,6 +708,8 @@ class AssignmentChecker
continue;
}
$property_exists = true;
if (ClassLikeChecker::checkPropertyVisibility(
$property_id,
$context->self,
@ -779,17 +787,7 @@ class AssignmentChecker
return null;
}
if (!$class_property_types) {
if (IssueBuffer::accepts(
new MissingPropertyDeclaration(
'Missing property declaration for ' . $var_id,
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
if (!$property_exists) {
return null;
}

View File

@ -1,6 +0,0 @@
<?php
namespace Psalm\Issue;
class MissingPropertyDeclaration extends CodeError
{
}

View File

@ -406,13 +406,14 @@ class AnnotationTest extends TestCase
* @property string $foo
*/
class A {
public function __get($name) : ?string {
public function __get(string $name) : ?string {
if ($name === "foo") {
return "hello";
}
}
public function __set($name, $value) : void {
/** @param mixed $value */
public function __set(string $name, $value) : void {
}
}

View File

@ -532,17 +532,6 @@ final class B extends A {}',
}',
'error_message' => 'UndefinedThisPropertyFetch',
],
'missingPropertyDeclaration' => [
'<?php
class A {
}
/** @psalm-suppress UndefinedPropertyAssignment */
function fooDo() : void {
(new A)->foo = "cool";
}',
'error_message' => 'MissingPropertyDeclaration',
],
'missingPropertyType' => [
'<?php
class A {