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

Fix #2920 - track unevaluated code after nested returns

This commit is contained in:
Matthew Brown 2020-03-15 14:31:41 -04:00
parent af9e362c80
commit 6c7f89b0ab
6 changed files with 55 additions and 10 deletions

View File

@ -352,6 +352,11 @@ class Context
*/
public $error_suppressing = false;
/**
* @var bool
*/
public $has_returned = false;
/**
* @param string|null $self
*/

View File

@ -496,6 +496,10 @@ class IfAnalyzer
$context->possibly_assigned_var_ids += $if_scope->possibly_assigned_var_ids;
}
if (!in_array(ScopeAnalyzer::ACTION_NONE, $if_scope->final_actions, true)) {
$context->has_returned = true;
}
return null;
}

View File

@ -277,6 +277,8 @@ class LoopAnalyzer
}
}
$inner_context->has_returned = false;
if ($inner_context->collect_references) {
foreach ($inner_context->unreferenced_vars as $var_id => $locations) {
if (!isset($pre_outer_context->vars_in_scope[$var_id])) {

View File

@ -85,6 +85,8 @@ class TryAnalyzer
return false;
}
$context->has_returned = false;
$stmt_control_actions = ScopeAnalyzer::getFinalControlActions(
$stmt->stmts,
$statements_analyzer->node_data,
@ -168,6 +170,7 @@ class TryAnalyzer
/** @var int $i */
foreach ($stmt->catches as $i => $catch) {
$catch_context = clone $original_context;
$catch_context->has_returned = false;
foreach ($catch_context->vars_in_scope as $var_id => $type) {
if (!isset($old_context->vars_in_scope[$var_id])) {

View File

@ -169,8 +169,6 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
Context $global_context = null,
$root_scope = false
) {
$has_returned = false;
// hoist functions to the top
foreach ($stmts as $stmt) {
if ($stmt instanceof PhpParser\Node\Stmt\Function_) {
@ -239,8 +237,11 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
$ignore_variable_property = false;
$ignore_variable_method = false;
if ($has_returned && !($stmt instanceof PhpParser\Node\Stmt\Nop) &&
!($stmt instanceof PhpParser\Node\Stmt\InlineHTML)
if ($context->has_returned
&& !$context->collect_initializations
&& !$context->collect_mutations
&& !($stmt instanceof PhpParser\Node\Stmt\Nop)
&& !($stmt instanceof PhpParser\Node\Stmt\InlineHTML)
) {
if ($context->collect_references) {
if (IssueBuffer::accepts(
@ -380,10 +381,10 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
} elseif ($stmt instanceof PhpParser\Node\Stmt\Unset_) {
$this->analyzeUnset($stmt, $context);
} elseif ($stmt instanceof PhpParser\Node\Stmt\Return_) {
$has_returned = true;
$context->has_returned = true;
ReturnAnalyzer::analyze($this, $stmt, $context);
} elseif ($stmt instanceof PhpParser\Node\Stmt\Throw_) {
$has_returned = true;
$context->has_returned = true;
ThrowAnalyzer::analyze($this, $stmt, $context);
} elseif ($stmt instanceof PhpParser\Node\Stmt\Switch_) {
SwitchAnalyzer::analyze($this, $stmt, $context);
@ -483,7 +484,7 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
}
}
$has_returned = true;
$context->has_returned = true;
} elseif ($stmt instanceof PhpParser\Node\Stmt\Continue_) {
$loop_scope = $context->loop_scope;
@ -575,7 +576,7 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
}
}
$has_returned = true;
$context->has_returned = true;
} elseif ($stmt instanceof PhpParser\Node\Stmt\Static_) {
$this->analyzeStatic($stmt, $context);
} elseif ($stmt instanceof PhpParser\Node\Stmt\Echo_) {
@ -865,7 +866,7 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
}
}
} elseif ($stmt instanceof PhpParser\Node\Stmt\HaltCompiler) {
$has_returned = true;
$context->has_returned = true;
} else {
if (IssueBuffer::accepts(
new UnrecognizedStatement(
@ -882,7 +883,7 @@ class StatementsAnalyzer extends SourceAnalyzer implements StatementsSource
&& $context->loop_scope->final_actions
&& !in_array(ScopeAnalyzer::ACTION_NONE, $context->loop_scope->final_actions, true)
) {
//$has_returned = true;
//$context->has_returned = true;
}
if ($plugin_classes) {

View File

@ -990,6 +990,36 @@ class UnusedCodeTest extends TestCase
}',
'error_message' => 'UnusedClass',
],
'returnInBothIfConditions' => [
'<?php
function doAThing(): bool {
if (rand(0, 1)) {
return true;
} else {
return false;
}
return false;
}',
'error_message' => 'UnevaluatedCode',
],
'unevaluatedCodeAfterReturnInFinally' => [
'<?php
function noOp(): void {
return;
}
function doAThing(): bool {
try {
noOp();
} finally {
return true;
}
return false;
}',
'error_message' => 'UnevaluatedCode',
],
];
}
}