1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Fix #5640 - improve handling of assignments in conditional

This commit is contained in:
Matt Brown 2021-04-18 16:16:54 -04:00
parent bb0bfda7c5
commit 642f2f435c
4 changed files with 69 additions and 20 deletions

View File

@ -147,12 +147,24 @@ class IfAnalyzer
if (!$has_break_statement) {
$if_scope->reasonable_clauses = [];
// If we're assigning inside
if ($if_conditional_scope->assigned_in_conditional_var_ids
&& $if_scope->post_leaving_if_context
) {
self::addConditionallyAssignedVarsToContext(
$statements_analyzer,
$stmt->cond,
$if_scope->post_leaving_if_context,
$outer_context,
$if_conditional_scope->assigned_in_conditional_var_ids
);
}
if (!$stmt->else && !$stmt->elseifs) {
$mic_drop = self::handleMicDrop(
$statements_analyzer,
$stmt->cond,
$if_scope,
$if_conditional_scope,
$outer_context,
$new_assigned_var_ids
);
@ -246,23 +258,9 @@ class IfAnalyzer
StatementsAnalyzer $statements_analyzer,
PhpParser\Node\Expr $cond,
IfScope $if_scope,
IfConditionalScope $if_conditional_scope,
Context $post_if_context,
array $new_assigned_var_ids
) : bool {
// If we're assigning inside
if ($if_conditional_scope->assigned_in_conditional_var_ids
&& $if_scope->post_leaving_if_context
) {
self::addConditionallyAssignedVarsToContext(
$statements_analyzer,
$cond,
$if_scope->post_leaving_if_context,
$post_if_context,
$if_conditional_scope->assigned_in_conditional_var_ids
);
}
if (!$if_scope->negated_types) {
return false;
}

View File

@ -68,10 +68,9 @@ class IfElseAnalyzer
$if_scope = new IfScope();
// We need to clone the original context for later use if we're exiting in this if conditional
if (!$stmt->else && !$stmt->elseifs
&& ($stmt->cond instanceof PhpParser\Node\Expr\BinaryOp
|| ($stmt->cond instanceof PhpParser\Node\Expr\BooleanNot
&& $stmt->cond->expr instanceof PhpParser\Node\Expr\BinaryOp))
if ($stmt->cond instanceof PhpParser\Node\Expr\BinaryOp
|| ($stmt->cond instanceof PhpParser\Node\Expr\BooleanNot
&& $stmt->cond->expr instanceof PhpParser\Node\Expr\BinaryOp)
) {
$final_actions = ScopeAnalyzer::getControlActions(
$stmt->stmts,
@ -368,7 +367,7 @@ class IfElseAnalyzer
}
// check the else
$else_context = clone $post_if_context;
$else_context = clone ($if_scope->post_leaving_if_context ?? $post_if_context);
// check the elseifs
foreach ($stmt->elseifs as $elseif) {

View File

@ -486,6 +486,41 @@ class AssignmentInConditionalTest extends \Psalm\Tests\TestCase
}',
'error_message' => 'InvalidReturnStatement',
],
'assignmentInBranchOfAndReferencedAfterIf' => [
'<?php
function bar(bool $result): bool {
if ($result && ($result = rand(0, 1))) {
return true;
}
return $result;
}',
'error_message' => 'InvalidReturnStatement',
],
'assignmentInBranchOfAndReferencedInElse' => [
'<?php
function bar(bool $result): bool {
if ($result && ($result = rand(0, 1))) {
return true;
} else {
return $result;
}
}',
'error_message' => 'InvalidReturnStatement',
],
'assignmentInBranchOfAndReferencedInElseIf' => [
'<?php
function bar(bool $result): bool {
if ($result && ($result = rand(0, 1))) {
return true;
} elseif (rand(0, 1)) {
return $result;
} else {
return true;
}
}',
'error_message' => 'InvalidReturnStatement',
],
];
}
}

View File

@ -2348,6 +2348,23 @@ class UnusedVariableTest extends TestCase
}
}'
],
'noUnusedVariableDefinedInBranchOfIf' => [
'<?php
abstract class Foo {
abstract function validate(): bool|string;
abstract function save(): bool|string;
function bar(): int {
if (($result = $this->validate()) && ($result = $this->save())) {
return 0;
} elseif (is_string($result)) {
return 1;
} else {
return 2;
}
}
}'
],
];
}