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

Fix isset assertions

This commit is contained in:
Matthew Brown 2016-09-22 12:26:24 -04:00
parent f44eed1d8c
commit 42c8923981
3 changed files with 56 additions and 7 deletions

View File

@ -378,6 +378,7 @@ class StatementsChecker
return false;
}
$forced_new_vars = null;
$new_vars = null;
$new_vars_possibly_in_scope = [];
$redefined_vars = null;
@ -395,9 +396,15 @@ class StatementsChecker
if (!$has_leaving_statements) {
$new_vars = array_diff_key($if_context->vars_in_scope, $context->vars_in_scope);
// if we have a check like if (!isset($a)) { $a = true; } we want to make sure $a is always set
foreach ($new_vars as $var_id => $type) {
if (isset($negated_if_types[$var_id]) && $negated_if_types[$var_id] === '!null') {
$forced_new_vars[$var_id] = Type::getMixed();
}
}
$redefined_vars = Context::getRedefinedVars($context, $if_context);
$possibly_redefined_vars = $redefined_vars;
}
elseif (!$stmt->else && !$stmt->elseifs && $negated_types) {
$context_vars_reconciled = TypeChecker::reconcileKeyedTypes(
@ -729,13 +736,14 @@ class StatementsChecker
}
}
if ($new_vars) {
$context->vars_in_scope = array_merge($context->vars_in_scope, $new_vars);
}
$context->vars_possibly_in_scope = array_merge($context->vars_possibly_in_scope, $new_vars_possibly_in_scope);
// vars can only be redefined if there was an else (defined in every block)
// vars can only be defined/redefined if there was an else (defined in every block)
if ($stmt->else) {
if ($new_vars) {
$context->vars_in_scope = array_merge($context->vars_in_scope, $new_vars);
}
if ($redefined_vars) {
foreach ($redefined_vars as $var => $type) {
$context->vars_in_scope[$var] = $type;
@ -750,6 +758,11 @@ class StatementsChecker
}
}
}
else {
if ($forced_new_vars) {
$context->vars_in_scope = array_merge($context->vars_in_scope, $forced_new_vars);
}
}
if ($possibly_redefined_vars) {
foreach ($possibly_redefined_vars as $var => $type) {

View File

@ -207,6 +207,7 @@ class ArrayAssignmentTest extends PHPUnit_Framework_TestCase
public function testConflictingTypesWithAssignment()
{
$this->markTestIncomplete('because object-like assigment isn\'t there yet');
$stmts = self::$_parser->parse('<?php
$foo = [
"bar" => ["a" => "b"],
@ -218,7 +219,7 @@ class ArrayAssignmentTest extends PHPUnit_Framework_TestCase
$file_checker = new \Psalm\Checker\FileChecker('somefile.php', $stmts);
$context = new Context('somefile.php');
$file_checker->check(true, true, $context);
$this->assertEquals('object-like{bar:array<string,string|array<string,string>>,baz:array<int,int>}', (string) $context->vars_in_scope['foo']);
$this->assertEquals('object-like{bar:object-like{a:string,bam:array<string,string>,baz:array<int,int>}', (string) $context->vars_in_scope['foo']);
}
public function testConflictingTypesWithAssignment2()
@ -266,6 +267,23 @@ class ArrayAssignmentTest extends PHPUnit_Framework_TestCase
$context = new Context('somefile.php');
$context->vars_in_scope['foo'] = \Psalm\Type::getArray();
$file_checker->check(true, true, $context);
$this->assertEquals('string', (string) $context->vars_in_scope['foo[\'a\']']);
$this->assertEquals('mixed', (string) $context->vars_in_scope['foo[\'a\']']);
}
public function testConditionalAssignment()
{
$file_checker = new \Psalm\Checker\FileChecker(
'somefile.php',
self::$_parser->parse('<?php
if ($b) {
$foo["a"] = "hello";
}
')
);
$context = new Context('somefile.php');
$context->vars_in_scope['b'] = \Psalm\Type::getBool();
$context->vars_in_scope['foo'] = \Psalm\Type::getArray();
$file_checker->check(true, true, $context);
$this->assertEquals(false, isset($context->vars_in_scope['foo[\'a\']']));
}
}

View File

@ -33,6 +33,24 @@ class ScopeTest extends PHPUnit_Framework_TestCase
\Psalm\Config::getInstance()->setIssueHandler('PossiblyUndefinedVariable', null);
}
/**
* @expectedException Psalm\Exception\CodeException
* @expectedExceptionMessage PossiblyUndefinedVariable - somefile.php:6 - Possibly undefined variable $b, first seen on line 3
*/
public function testPossiblyUndefinedVarInIf()
{
$stmts = self::$_parser->parse('<?php
if (rand(0,100) === 10) {
$b = "s";
}
echo $b;
');
$file_checker = new \Psalm\Checker\FileChecker('somefile.php', $stmts);
$file_checker->check();
}
public function testNewVarInIf()
{
$stmts = self::$_parser->parse('<?php