1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Don’t manipulate property storage during analysis

This commit is contained in:
Brown 2020-07-07 19:32:44 -04:00
parent ee8619f7bb
commit 0034f2e4bd
3 changed files with 45 additions and 19 deletions

View File

@ -55,6 +55,11 @@ use function array_keys;
*/ */
class ClassAnalyzer extends ClassLikeAnalyzer class ClassAnalyzer extends ClassLikeAnalyzer
{ {
/**
* @var array<string, Type\Union>
*/
public $inferred_property_types = [];
/** /**
* @param PhpParser\Node\Stmt\Class_ $class * @param PhpParser\Node\Stmt\Class_ $class
* @param SourceAnalyzer $source * @param SourceAnalyzer $source
@ -1630,11 +1635,23 @@ class ClassAnalyzer extends ClassLikeAnalyzer
$property_storage = $class_storage->properties[$property_name]; $property_storage = $class_storage->properties[$property_name];
if ($property_storage->suggested_type && !$property_storage->suggested_type->isNull()) { $suggested_type = $property_storage->suggested_type;
if (isset($this->inferred_property_types[$property_name])) {
$suggested_type = $suggested_type
? Type::combineUnionTypes(
$suggested_type,
$this->inferred_property_types[$property_name],
$codebase
)
: $this->inferred_property_types[$property_name];
}
if ($suggested_type && !$suggested_type->isNull()) {
$message .= ' - consider ' . str_replace( $message .= ' - consider ' . str_replace(
['<mixed, mixed>', '<empty, empty>'], ['<array-key, mixed>', '<empty, empty>'],
'', '',
(string)$property_storage->suggested_type (string)$suggested_type
); );
} }

View File

@ -4,6 +4,7 @@ namespace Psalm\Internal\Analyzer\Statements\Expression\Assignment;
use PhpParser; use PhpParser;
use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\PropertyProperty; use PhpParser\Node\Stmt\PropertyProperty;
use Psalm\Internal\Analyzer\ClassAnalyzer;
use Psalm\Internal\Analyzer\ClassLikeAnalyzer; use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
use Psalm\Internal\Analyzer\NamespaceAnalyzer; use Psalm\Internal\Analyzer\NamespaceAnalyzer;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer; use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
@ -660,8 +661,6 @@ class InstancePropertyAssignmentAnalyzer
$declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); $declaring_class_storage = $codebase->classlike_storage_provider->get($declaring_property_class);
$property_storage = null;
if (isset($declaring_class_storage->properties[$prop_name])) { if (isset($declaring_class_storage->properties[$prop_name])) {
$property_storage = $declaring_class_storage->properties[$prop_name]; $property_storage = $declaring_class_storage->properties[$prop_name];
@ -763,15 +762,19 @@ class InstancePropertyAssignmentAnalyzer
if (!$class_property_type) { if (!$class_property_type) {
$class_property_type = Type::getMixed(); $class_property_type = Type::getMixed();
if (!$assignment_value_type->hasMixed() && $property_storage) { $source_analyzer = $statements_analyzer->getSource()->getSource();
if ($property_storage->suggested_type) {
$property_storage->suggested_type = Type::combineUnionTypes( if (!$assignment_value_type->hasMixed()
&& $lhs_var_id === '$this'
&& $source_analyzer instanceof ClassAnalyzer
) {
if (isset($source_analyzer->inferred_property_types[$prop_name])) {
$source_analyzer->inferred_property_types[$prop_name] = Type::combineUnionTypes(
$assignment_value_type, $assignment_value_type,
$property_storage->suggested_type $source_analyzer->inferred_property_types[$prop_name]
); );
} else { } else {
$property_storage->suggested_type = $source_analyzer->inferred_property_types[$prop_name] =
$lhs_var_id === '$this' &&
($context->inside_constructor || $context->collect_initializations) ($context->inside_constructor || $context->collect_initializations)
? $assignment_value_type ? $assignment_value_type
: Type::combineUnionTypes(Type::getNull(), $assignment_value_type); : Type::combineUnionTypes(Type::getNull(), $assignment_value_type);

View File

@ -4,6 +4,7 @@ namespace Psalm\Internal\Analyzer\Statements\Expression\Assignment;
use PhpParser; use PhpParser;
use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\PropertyProperty; use PhpParser\Node\Stmt\PropertyProperty;
use Psalm\Internal\Analyzer\ClassAnalyzer;
use Psalm\Internal\Analyzer\ClassLikeAnalyzer; use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
use Psalm\Internal\Analyzer\NamespaceAnalyzer; use Psalm\Internal\Analyzer\NamespaceAnalyzer;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer; use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
@ -173,8 +174,6 @@ class StaticPropertyAssignmentAnalyzer
$class_storage = $codebase->classlike_storage_provider->get($declaring_property_class); $class_storage = $codebase->classlike_storage_provider->get($declaring_property_class);
$property_storage = $class_storage->properties[$prop_name->name];
if ($var_id) { if ($var_id) {
$context->vars_in_scope[$var_id] = $assignment_value_type; $context->vars_in_scope[$var_id] = $assignment_value_type;
} }
@ -189,14 +188,21 @@ class StaticPropertyAssignmentAnalyzer
if (!$class_property_type) { if (!$class_property_type) {
$class_property_type = Type::getMixed(); $class_property_type = Type::getMixed();
if (!$assignment_value_type->hasMixed()) { $source_analyzer = $statements_analyzer->getSource()->getSource();
if ($property_storage->suggested_type) {
$property_storage->suggested_type = Type::combineUnionTypes( $prop_name_name = $prop_name->name;
if (!$assignment_value_type->hasMixed()
&& $source_analyzer instanceof ClassAnalyzer
&& $fq_class_name === $source_analyzer->getFQCLN()
) {
if (isset($source_analyzer->inferred_property_types[$prop_name_name])) {
$source_analyzer->inferred_property_types[$prop_name_name] = Type::combineUnionTypes(
$assignment_value_type, $assignment_value_type,
$property_storage->suggested_type $source_analyzer->inferred_property_types[$prop_name_name]
); );
} else { } else {
$property_storage->suggested_type = Type::combineUnionTypes( $source_analyzer->inferred_property_types[$prop_name_name] = Type::combineUnionTypes(
Type::getNull(), Type::getNull(),
$assignment_value_type $assignment_value_type
); );