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

Improve handling of property-mutating calls

This commit is contained in:
Matt Brown 2021-02-10 12:09:21 -05:00
parent 2dc86651a4
commit ccdb29abfa

View File

@ -4,6 +4,7 @@ namespace Psalm\Internal\Analyzer\Statements\Expression\Call\Method;
use PhpParser;
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\Analyzer\Statements\Expression\Call\ClassTemplateParamCollector;
use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\Context;
@ -145,16 +146,83 @@ class MethodCallPurityAnalyzer
&& isset($context->vars_in_scope[$mutation_var_id])
&& !isset($class_storage->declaring_property_ids[$name]);
$current_context = $context;
do {
$current_context->remove($mutation_var_id);
} while ($current_context = $current_context->parent_context);
if ($this_property_didnt_exist) {
$context->vars_in_scope[$mutation_var_id] = Type::getMixed();
} else {
$context->vars_in_scope[$mutation_var_id] = self::getExpandedPropertyType(
$codebase,
$class_storage->name,
$name,
$class_storage
) ?: Type::getMixed();
}
}
}
}
private static function getExpandedPropertyType(
Codebase $codebase,
string $fq_class_name,
string $property_name,
\Psalm\Storage\ClassLikeStorage $storage
) : ?Type\Union {
$property_class_name = $codebase->properties->getDeclaringClassForProperty(
$fq_class_name . '::$' . $property_name,
true
);
if ($property_class_name === null) {
return null;
}
$property_class_storage = $codebase->classlike_storage_provider->get($property_class_name);
$property_storage = $property_class_storage->properties[$property_name];
if (!$property_storage->type) {
return null;
}
$property_type = clone $property_storage->type;
$fleshed_out_type = !$property_type->isMixed()
? \Psalm\Internal\Type\TypeExpander::expandUnion(
$codebase,
$property_type,
$fq_class_name,
$fq_class_name,
$storage->parent_class,
true,
false,
$storage->final
)
: $property_type;
$class_template_params = ClassTemplateParamCollector::collect(
$codebase,
$property_class_storage,
$storage,
null,
new Type\Atomic\TNamedObject($fq_class_name),
true
);
$template_result = new \Psalm\Internal\Type\TemplateResult(
$class_template_params ?: [],
[]
);
if ($class_template_params) {
$fleshed_out_type = \Psalm\Internal\Type\TemplateStandinTypeReplacer::replace(
$fleshed_out_type,
$template_result,
$codebase,
null,
null,
null
);
}
return $fleshed_out_type;
}
}