1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Improve reconciliation of ||

Ref #2426
This commit is contained in:
Brown 2020-01-06 16:37:44 -05:00
parent 578b90c2da
commit 5c45221bdc
2 changed files with 63 additions and 45 deletions

View File

@ -295,45 +295,70 @@ class BinaryOpAnalyzer
return null;
}
$pre_referenced_var_ids = $context->referenced_var_ids;
$context->referenced_var_ids = [];
if (!$stmt->left instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr
&& !($stmt->left instanceof PhpParser\Node\Expr\BooleanNot
&& $stmt->left->expr instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd)
) {
$if_scope = new \Psalm\Internal\Scope\IfScope();
$pre_assigned_var_ids = $context->assigned_var_ids;
$left_context = clone $context;
$left_context->parent_context = $context;
$left_context->if_context = null;
$left_context->assigned_var_ids = [];
if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->left, $left_context) === false) {
return false;
}
foreach ($left_context->vars_in_scope as $var_id => $type) {
if (!isset($context->vars_in_scope[$var_id])) {
if (isset($left_context->assigned_var_ids[$var_id])) {
$context->vars_in_scope[$var_id] = clone $type;
}
} else {
$context->vars_in_scope[$var_id] = Type::combineUnionTypes(
$context->vars_in_scope[$var_id],
$type,
$codebase
try {
$if_conditional_scope = IfAnalyzer::analyzeIfConditional(
$statements_analyzer,
$stmt->left,
$context,
$codebase,
$if_scope,
$context->branch_point ?: (int) $stmt->getAttribute('startFilePos')
);
$left_context = $if_conditional_scope->if_context;
$left_referenced_var_ids = $if_conditional_scope->cond_referenced_var_ids;
$left_assigned_var_ids = $if_conditional_scope->cond_assigned_var_ids;
} catch (\Psalm\Exception\ScopeAnalysisException $e) {
return false;
}
} else {
$pre_referenced_var_ids = $context->referenced_var_ids;
$context->referenced_var_ids = [];
$pre_assigned_var_ids = $context->assigned_var_ids;
$left_context = clone $context;
$left_context->parent_context = $context;
$left_context->if_context = null;
$left_context->assigned_var_ids = [];
if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->left, $left_context) === false) {
return false;
}
foreach ($left_context->vars_in_scope as $var_id => $type) {
if (!isset($context->vars_in_scope[$var_id])) {
if (isset($left_context->assigned_var_ids[$var_id])) {
$context->vars_in_scope[$var_id] = clone $type;
}
} else {
$context->vars_in_scope[$var_id] = Type::combineUnionTypes(
$context->vars_in_scope[$var_id],
$type,
$codebase
);
}
}
if ($context->collect_references) {
$context->unreferenced_vars = $left_context->unreferenced_vars;
}
$left_referenced_var_ids = $left_context->referenced_var_ids;
$left_context->referenced_var_ids = array_merge($pre_referenced_var_ids, $left_referenced_var_ids);
$left_assigned_var_ids = array_diff_key($left_context->assigned_var_ids, $pre_assigned_var_ids);
$left_referenced_var_ids = array_diff_key($left_referenced_var_ids, $left_assigned_var_ids);
}
if ($context->collect_references) {
$context->unreferenced_vars = $left_context->unreferenced_vars;
}
$left_referenced_var_ids = $left_context->referenced_var_ids;
$left_context->referenced_var_ids = array_merge($pre_referenced_var_ids, $left_referenced_var_ids);
$left_assigned_var_ids = array_diff_key($left_context->assigned_var_ids, $pre_assigned_var_ids);
$left_referenced_var_ids = array_diff_key($left_referenced_var_ids, $left_assigned_var_ids);
$left_clauses = Algebra::getFormula(
\spl_object_id($stmt->left),
$stmt->left,

View File

@ -2498,7 +2498,7 @@ class ConditionalTest extends \Psalm\Tests\TestCase
return 0;
}',
],
'SKIPPED-assertHardConditional' => [
'assertHardConditionalWithString' => [
'<?php
interface Convertor {
function maybeConvert(string $value): ?SomeObject;
@ -2508,19 +2508,12 @@ class ConditionalTest extends \Psalm\Tests\TestCase
function isValid(): bool;
}
/**
* @param mixed $value
*/
function exampleWithOr(Convertor $convertor, $value): SomeObject
{
if (!\is_string($value)
|| ($value = $convertor->maybeConvert($value)) === null
|| !$value->isValid()
) {
function exampleWithOr(Convertor $convertor, string $value): SomeObject {
if (($value = $convertor->maybeConvert($value)) === null || !$value->isValid()) {
throw new Exception();
}
return $value;
return $value; // $value is SomeObject here and cannot be a string
}'
],
];