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:
parent
f44eed1d8c
commit
42c8923981
@ -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) {
|
||||
|
@ -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\']']));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user