1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-02 17:52:45 +01:00

Improve typing of properties

This commit is contained in:
Matthew Brown 2016-09-12 11:32:44 -04:00
parent 677614f23e
commit 6a9bcea901
2 changed files with 98 additions and 22 deletions

View File

@ -342,9 +342,21 @@ abstract class ClassLikeChecker implements StatementsSource
$type_in_comment = CommentChecker::getTypeFromComment((string) $comment, null, $this);
}
$property_type = $type_in_comment ? $type_in_comment : Type::getMixed();
$property_group_type = $type_in_comment ? $type_in_comment : null;
foreach ($stmt->props as $property) {
if (!$property_group_type) {
if (!$property->default) {
$property_type = Type::getMixed();
}
else {
$property_type = StatementsChecker::getSimpleType($property->default) ?: Type::getMixed();
}
}
else {
$property_type = $property_group_type;
}
if ($stmt->isStatic()) {
if ($stmt->isPublic()) {
self::$public_static_class_properties[$class_context->self][$property->name] = $property_type;
@ -367,10 +379,6 @@ abstract class ClassLikeChecker implements StatementsSource
self::$private_class_properties[$class_context->self][$property->name] = $property_type;
}
}
if (!$stmt->isStatic()) {
$class_context->vars_in_scope['this->' . $property->name] = $property_type;
}
}
}
elseif ($stmt instanceof PhpParser\Node\Stmt\ClassConst) {
@ -400,6 +408,16 @@ abstract class ClassLikeChecker implements StatementsSource
(new StatementsChecker($this))->check($leftover_stmts, $class_context);
}
$all_instance_properties = array_merge(
self::$public_class_properties[$this->absolute_class],
self::$protected_class_properties[$this->absolute_class],
self::$private_class_properties[$this->absolute_class]
);
foreach ($all_instance_properties as $property_name => $property_type) {
$class_context->vars_in_scope['this->' . $property_name] = $property_type;
}
$config = Config::getInstance();
if ($check_methods) {

View File

@ -1129,6 +1129,50 @@ class StatementsChecker
}
}
public static function getSimpleType(PhpParser\Node\Expr $stmt)
{
if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) {
// @todo support this
}
elseif ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) {
// @todo support this as well
}
elseif ($stmt instanceof PhpParser\Node\Scalar\String_) {
return Type::getString();
}
elseif ($stmt instanceof PhpParser\Node\Scalar\LNumber) {
return Type::getInt();
}
elseif ($stmt instanceof PhpParser\Node\Scalar\DNumber) {
return Type::getFloat();
}
elseif ($stmt instanceof PhpParser\Node\Expr\Array_) {
return Type::getArray();
}
elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Int_) {
return Type::getInt();
}
elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Double) {
return Type::getFloat();
}
elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Bool_) {
return Type::getBool();
}
elseif ($stmt instanceof PhpParser\Node\Expr\Cast\String_) {
return Type::getString();
}
elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Object_) {
return Type::getObject();
}
elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Array_) {
return Type::getArray();
}
else {
var_dump('Unrecognised default property type in ' . $this->checked_file_name);
var_dump($stmt);
}
}
/**
* @param PhpParser\Node\Expr\Variable|PhpParser\Node\Expr\PropertyFetch $stmt
* @param string $method_id
@ -2232,29 +2276,36 @@ class StatementsChecker
}
}
if ($nesting) {
$context_type = clone $context->vars_in_scope[$var_id];
if ($return_type) {
if ($nesting && $var_id) {
$context_type = clone $context->vars_in_scope[$var_id];
$array_type = $context_type;
$array_type = $context_type;
for ($i = 0; $i < $nesting + 1; $i++) {
if ($i < $nesting) {
if ($array_type->types['array']->type_params[1]->isEmpty()) {
$array_type->types['array']->type_params[1] = $return_type;
break;
for ($i = 0; $i < $nesting + 1; $i++) {
if ($array_type->isArray()) {
if ($i < $nesting) {
if ($array_type->types['array']->type_params[1]->isEmpty()) {
$array_type->types['array']->type_params[1] = $return_type;
break;
}
$array_type = $array_type->types['array']->type_params[1];
}
else {
$array_type->types['array']->type_params[1] = $return_type->types['array']->type_params[1];
}
}
}
$array_type = $array_type->types['array']->type_params[1];
}
else {
$array_type->types['array']->type_params[1] = $return_type->types['array']->type_params[1];
}
$context->vars_in_scope[$var_id] = $context_type;
}
else {
$context->vars_in_scope[$var_id] = $return_type;
}
$context->vars_in_scope[$var_id] = $context_type;
}
else {
$context->vars_in_scope[$var_id] = $return_type;
$context->vars_in_scope[$var_id] = Type::getMixed();
}
}
}
@ -2289,10 +2340,15 @@ class StatementsChecker
}
}
if ($type->isMixed()) {
// @todo emit issue
return;
}
if ($type->value !== 'array' && !ClassChecker::classImplements($type->value, 'ArrayAccess')) {
if (IssueBuffer::accepts(
new InvalidArrayAssignment(
'Cannot assign value on variable ' . $var_id . ' that does not implement ArrayAccess',
'Cannot assign value on variable $' . $var_id . ' of type ' . $type->value . ' that does not implement ArrayAccess',
$this->checked_file_name,
$line_number
),
@ -3621,6 +3677,8 @@ class StatementsChecker
return false;
}
}
$stmt->inferredType = Type::getString();
}
public function registerVariable($var_name, $line_number)