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); $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) { 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->isStatic()) {
if ($stmt->isPublic()) { if ($stmt->isPublic()) {
self::$public_static_class_properties[$class_context->self][$property->name] = $property_type; 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; 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) { elseif ($stmt instanceof PhpParser\Node\Stmt\ClassConst) {
@ -400,6 +408,16 @@ abstract class ClassLikeChecker implements StatementsSource
(new StatementsChecker($this))->check($leftover_stmts, $class_context); (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(); $config = Config::getInstance();
if ($check_methods) { 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 PhpParser\Node\Expr\Variable|PhpParser\Node\Expr\PropertyFetch $stmt
* @param string $method_id * @param string $method_id
@ -2232,29 +2276,36 @@ class StatementsChecker
} }
} }
if ($nesting) { if ($return_type) {
$context_type = clone $context->vars_in_scope[$var_id]; 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++) { for ($i = 0; $i < $nesting + 1; $i++) {
if ($i < $nesting) { if ($array_type->isArray()) {
if ($array_type->types['array']->type_params[1]->isEmpty()) { if ($i < $nesting) {
$array_type->types['array']->type_params[1] = $return_type; if ($array_type->types['array']->type_params[1]->isEmpty()) {
break; $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]; $context->vars_in_scope[$var_id] = $context_type;
} }
else { else {
$array_type->types['array']->type_params[1] = $return_type->types['array']->type_params[1]; $context->vars_in_scope[$var_id] = $return_type;
}
} }
$context->vars_in_scope[$var_id] = $context_type;
} }
else { 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 ($type->value !== 'array' && !ClassChecker::classImplements($type->value, 'ArrayAccess')) {
if (IssueBuffer::accepts( if (IssueBuffer::accepts(
new InvalidArrayAssignment( 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, $this->checked_file_name,
$line_number $line_number
), ),
@ -3621,6 +3677,8 @@ class StatementsChecker
return false; return false;
} }
} }
$stmt->inferredType = Type::getString();
} }
public function registerVariable($var_name, $line_number) public function registerVariable($var_name, $line_number)