mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Fix issue evaluating elseif empty assertions
This commit is contained in:
parent
9dd94d099f
commit
6cfe540c98
@ -440,6 +440,8 @@ class IfChecker
|
||||
$elseif_context->vars_in_scope = $elseif_vars_reconciled;
|
||||
}
|
||||
|
||||
$pre_conditional_context = clone $elseif_context;
|
||||
|
||||
$elseif_context->inside_conditional = true;
|
||||
|
||||
// check the elseif
|
||||
@ -591,25 +593,43 @@ class IfChecker
|
||||
}
|
||||
|
||||
if ($negated_elseif_types) {
|
||||
$negated_keys = [];
|
||||
if ($has_leaving_statements) {
|
||||
$changed_vars = [];
|
||||
|
||||
foreach ($negated_elseif_types as $var_id => $type) {
|
||||
if (!$has_leaving_statements ||
|
||||
$type !== '!empty' ||
|
||||
!isset($elseif_context->vars_in_scope[$var_id]) ||
|
||||
$elseif_context->vars_in_scope[$var_id]->hasObjectType()
|
||||
) {
|
||||
$negated_keys[] = $var_id;
|
||||
$leaving_vars_reconciled = TypeChecker::reconcileKeyedTypes(
|
||||
$negated_elseif_types,
|
||||
$pre_conditional_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
new CodeLocation($statements_checker->getSource(), $elseif),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
|
||||
if ($leaving_vars_reconciled === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$outer_context->update(
|
||||
$old_elseif_context,
|
||||
$elseif_context,
|
||||
$has_leaving_statements,
|
||||
$negated_keys,
|
||||
$if_scope->updated_vars
|
||||
);
|
||||
$implied_outer_context = clone $elseif_context;
|
||||
$implied_outer_context->vars_in_scope = $leaving_vars_reconciled;
|
||||
|
||||
$outer_context->update(
|
||||
$elseif_context,
|
||||
$implied_outer_context,
|
||||
false,
|
||||
array_keys($negated_elseif_types),
|
||||
$if_scope->updated_vars
|
||||
);
|
||||
} else {
|
||||
$negated_keys = [];
|
||||
|
||||
$outer_context->update(
|
||||
$old_elseif_context,
|
||||
$elseif_context,
|
||||
false,
|
||||
array_keys($negated_elseif_types),
|
||||
$if_scope->updated_vars
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$has_ending_statements) {
|
||||
|
@ -339,7 +339,7 @@ class StatementsChecker extends SourceChecker implements StatementsSource
|
||||
Context $outer_context
|
||||
) {
|
||||
// record all the vars that existed before we did the first pass through the loop
|
||||
$pre_loop_vars_in_scope = $loop_context->vars_in_scope;
|
||||
$pre_loop_context = clone $loop_context;
|
||||
|
||||
IssueBuffer::startRecording();
|
||||
$this->analyze($stmts, $loop_context, $outer_context);
|
||||
@ -352,10 +352,10 @@ class StatementsChecker extends SourceChecker implements StatementsSource
|
||||
|
||||
// widen the foreach context type with the initial context type
|
||||
foreach ($loop_context->vars_in_scope as $var_id => $type) {
|
||||
if (isset($pre_loop_vars_in_scope[$var_id])) {
|
||||
if (isset($pre_loop_context->vars_in_scope[$var_id])) {
|
||||
$loop_context->vars_in_scope[$var_id] = Type::combineUnionTypes(
|
||||
$type,
|
||||
$pre_loop_vars_in_scope[$var_id]
|
||||
$pre_loop_context->vars_in_scope[$var_id]
|
||||
);
|
||||
|
||||
if (isset($outer_context->vars_in_scope[$var_id])) {
|
||||
|
@ -441,6 +441,37 @@ class LoopScopeTest extends PHPUnit_Framework_TestCase
|
||||
$file_checker->visitAndAnalyzeMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testSecondLoopWithReturnInElseif()
|
||||
{
|
||||
$stmts = self::$parser->parse('<?php
|
||||
class A {}
|
||||
class B extends A {}
|
||||
class C extends A {}
|
||||
|
||||
$b = null;
|
||||
|
||||
foreach ([new A, new A] as $a) {
|
||||
if ($a instanceof B) {
|
||||
|
||||
} elseif (!$a instanceof C) {
|
||||
return "goodbye";
|
||||
}
|
||||
|
||||
if ($b instanceof C) {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
$b = $a;
|
||||
}
|
||||
');
|
||||
|
||||
$file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts);
|
||||
$file_checker->visitAndAnalyzeMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
@ -883,6 +883,30 @@ class TypeReconciliationTest extends PHPUnit_Framework_TestCase
|
||||
$file_checker->visitAndAnalyzeMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testEmptyExceptionReconciliationAfterIf()
|
||||
{
|
||||
$stmts = self::$parser->parse('<?php
|
||||
/**
|
||||
* @param Exception|null $a
|
||||
*/
|
||||
function foo($a) : string {
|
||||
if ($a && $a->getMessage() === "hello") {
|
||||
return "hello";
|
||||
} elseif (empty($a)) {
|
||||
return "goodbye";
|
||||
}
|
||||
|
||||
return $a->getMessage();
|
||||
}
|
||||
');
|
||||
|
||||
$file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts);
|
||||
$file_checker->visitAndAnalyzeMethods();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user