1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-02 09:37:59 +01:00

Add more accurate checks for assignment

This commit is contained in:
Matthew Brown 2016-01-20 14:19:47 -05:00
parent 0d9059b333
commit 08c4c03854

View File

@ -654,10 +654,13 @@ class StatementsChecker
protected function _checkAssignment(PhpParser\Node\Expr\Assign $stmt, array &$vars_in_scope, array &$vars_possibly_in_scope) protected function _checkAssignment(PhpParser\Node\Expr\Assign $stmt, array &$vars_in_scope, array &$vars_possibly_in_scope)
{ {
$this->_checkExpression($stmt->expr, $vars_in_scope, $vars_possibly_in_scope);
if ($stmt->var instanceof PhpParser\Node\Expr\Variable && is_string($stmt->var->name)) { if ($stmt->var instanceof PhpParser\Node\Expr\Variable && is_string($stmt->var->name)) {
$vars_in_scope[$stmt->var->name] = true; $vars_in_scope[$stmt->var->name] = true;
$vars_possibly_in_scope[$stmt->var->name] = true; $vars_possibly_in_scope[$stmt->var->name] = true;
$this->registerVariable($stmt->var->name, $stmt->var->getLine()); $this->registerVariable($stmt->var->name, $stmt->var->getLine());
} elseif ($stmt->var instanceof PhpParser\Node\Expr\List_) { } elseif ($stmt->var instanceof PhpParser\Node\Expr\List_) {
foreach ($stmt->var->vars as $var) { foreach ($stmt->var->vars as $var) {
if ($var) { if ($var) {
@ -666,16 +669,14 @@ class StatementsChecker
$this->registerVariable($var->name, $var->getLine()); $this->registerVariable($var->name, $var->getLine());
} }
} }
}
} else if ($stmt->var instanceof PhpParser\Node\Expr\ArrayDimFetch && $stmt->var->var instanceof PhpParser\Node\Expr\Variable) {
// if it's an array assignment // if it's an array assignment
else if ($stmt->var instanceof PhpParser\Node\Expr\ArrayDimFetch && $stmt->var->var instanceof PhpParser\Node\Expr\Variable) {
$vars_in_scope[$stmt->var->var->name] = true; $vars_in_scope[$stmt->var->var->name] = true;
$vars_possibly_in_scope[$stmt->var->var->name] = true; $vars_possibly_in_scope[$stmt->var->var->name] = true;
$this->registerVariable($stmt->var->var->name, $stmt->var->var->getLine()); $this->registerVariable($stmt->var->var->name, $stmt->var->var->getLine());
} }
$this->_checkExpression($stmt->expr, $vars_in_scope, $vars_possibly_in_scope);
if ($stmt->var instanceof PhpParser\Node\Expr\Variable && is_string($stmt->var->name)) { if ($stmt->var instanceof PhpParser\Node\Expr\Variable && is_string($stmt->var->name)) {
$comments = []; $comments = [];
$doc_comment = $stmt->getDocComment(); $doc_comment = $stmt->getDocComment();
@ -690,6 +691,7 @@ class StatementsChecker
if ($type[0] === strtoupper($type[0])) { if ($type[0] === strtoupper($type[0])) {
$vars_in_scope[$stmt->var->name] = ClassChecker::getAbsoluteClassFromString($type, $this->_namespace, $this->_aliased_classes); $vars_in_scope[$stmt->var->name] = ClassChecker::getAbsoluteClassFromString($type, $this->_namespace, $this->_aliased_classes);
} }
} elseif (isset($stmt->expr->returnType)) { } elseif (isset($stmt->expr->returnType)) {
$var_name = $stmt->var->name; $var_name = $stmt->var->name;
@ -697,6 +699,7 @@ class StatementsChecker
if (isset($vars_in_scope[$var_name])) { if (isset($vars_in_scope[$var_name])) {
$vars_in_scope[$var_name] = 'mixed'; $vars_in_scope[$var_name] = 'mixed';
} }
} elseif (isset($vars_in_scope[$var_name])) { } elseif (isset($vars_in_scope[$var_name])) {
$existing_type = $vars_in_scope[$var_name]; $existing_type = $vars_in_scope[$var_name];
@ -711,6 +714,7 @@ class StatementsChecker
$vars_in_scope[$stmt->var->name] = 'mixed'; $vars_in_scope[$stmt->var->name] = 'mixed';
} }
} }
} else { } else {
$vars_in_scope[$stmt->var->name] = $stmt->expr->returnType; $vars_in_scope[$stmt->var->name] = $stmt->expr->returnType;
} }
@ -973,6 +977,9 @@ class StatementsChecker
} elseif ($method->parts === ['defined']) { } elseif ($method->parts === ['defined']) {
$this->_check_consts = false; $this->_check_consts = false;
} elseif ($method->parts === ['extract']) {
$this->_check_variables = false;
} elseif ($method->parts === ['var_dump'] || $method->parts === ['die'] || $method->parts === ['exit']) { } elseif ($method->parts === ['var_dump'] || $method->parts === ['die'] || $method->parts === ['exit']) {
if (FileChecker::shouldCheckVarDumps($this->_file_name)) { if (FileChecker::shouldCheckVarDumps($this->_file_name)) {
throw new CodeException('Unsafe ' . implode('', $method->parts), $this->_file_name, $stmt->getLine()); throw new CodeException('Unsafe ' . implode('', $method->parts), $this->_file_name, $stmt->getLine());