mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Fix #3808 - allow detection of paradoxes in switch condition function calls
This commit is contained in:
parent
f0a5463834
commit
3c9028c182
@ -46,6 +46,19 @@ class SwitchAnalyzer
|
||||
$statements_analyzer
|
||||
);
|
||||
|
||||
if (!$switch_var_id
|
||||
&& ($stmt->cond instanceof PhpParser\Node\Expr\FuncCall
|
||||
|| $stmt->cond instanceof PhpParser\Node\Expr\MethodCall
|
||||
|| $stmt->cond instanceof PhpParser\Node\Expr\StaticCall
|
||||
)
|
||||
) {
|
||||
$switch_var_id = '$__tmp_switch__' . (int) $stmt->cond->getAttribute('startFilePos');
|
||||
|
||||
$condition_type = $statements_analyzer->node_data->getType($stmt->cond) ?: Type::getMixed();
|
||||
|
||||
$context->vars_in_scope[$switch_var_id] = $condition_type;
|
||||
}
|
||||
|
||||
$original_context = clone $context;
|
||||
|
||||
// the last statement always breaks, by default
|
||||
|
@ -65,6 +65,19 @@ class SwitchCaseAnalyzer
|
||||
|
||||
$old_node_data = $statements_analyzer->node_data;
|
||||
|
||||
$fake_switch_condition = false;
|
||||
|
||||
if ($switch_var_id && substr($switch_var_id, 0, 15) === '$__tmp_switch__') {
|
||||
$switch_condition = new PhpParser\Node\Expr\Variable(
|
||||
substr($switch_var_id, 1),
|
||||
$stmt->cond->getAttributes()
|
||||
);
|
||||
|
||||
$fake_switch_condition = true;
|
||||
} else {
|
||||
$switch_condition = $stmt->cond;
|
||||
}
|
||||
|
||||
if ($case->cond) {
|
||||
$was_inside_conditional = $case_context->inside_conditional;
|
||||
$case_context->inside_conditional = true;
|
||||
@ -92,7 +105,14 @@ class SwitchCaseAnalyzer
|
||||
);
|
||||
|
||||
/** @var PhpParser\Node\Expr */
|
||||
$switch_condition = $traverser->traverse([$stmt->cond])[0];
|
||||
$switch_condition = $traverser->traverse([$switch_condition])[0];
|
||||
|
||||
if ($fake_switch_condition) {
|
||||
$statements_analyzer->node_data->setType(
|
||||
$switch_condition,
|
||||
$case_context->vars_in_scope[$switch_var_id] ?? Type::getMixed()
|
||||
);
|
||||
}
|
||||
|
||||
if ($switch_condition instanceof PhpParser\Node\Expr\Variable
|
||||
&& is_string($switch_condition->name)
|
||||
@ -129,6 +149,13 @@ class SwitchCaseAnalyzer
|
||||
|
||||
if ($type_statements && count($type_statements) === 1) {
|
||||
$switch_condition = $type_statements[0];
|
||||
|
||||
if ($fake_switch_condition) {
|
||||
$statements_analyzer->node_data->setType(
|
||||
$switch_condition,
|
||||
$case_context->vars_in_scope[$switch_var_id] ?? Type::getMixed()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,13 +255,13 @@ class SwitchCaseAnalyzer
|
||||
}
|
||||
|
||||
if ($case_equality_expr
|
||||
&& $stmt->cond instanceof PhpParser\Node\Expr\Variable
|
||||
&& is_string($stmt->cond->name)
|
||||
&& isset($context->vars_in_scope['$' . $stmt->cond->name])
|
||||
&& $switch_condition instanceof PhpParser\Node\Expr\Variable
|
||||
&& is_string($switch_condition->name)
|
||||
&& isset($context->vars_in_scope['$' . $switch_condition->name])
|
||||
) {
|
||||
$new_case_equality_expr = self::simplifyCaseEqualityExpression(
|
||||
$case_equality_expr,
|
||||
$stmt->cond
|
||||
$switch_condition
|
||||
);
|
||||
|
||||
if ($new_case_equality_expr) {
|
||||
|
@ -1188,7 +1188,25 @@ class SwitchTypeTest extends TestCase
|
||||
break;
|
||||
}
|
||||
}',
|
||||
'error_message' => 'TypeDoesNotContainType - src' . DIRECTORY_SEPARATOR . 'somefile.php:5:34 - string(InvalidArgumentException) cannot be identical to class-string',
|
||||
'error_message' => 'TypeDoesNotContainType',
|
||||
],
|
||||
'paradoxInFunctionCall' => [
|
||||
'<?php
|
||||
/** @psalm-return 1|2|3 */
|
||||
function foo() {
|
||||
/** @psalm-var 1|2|3 $bar */
|
||||
$bar = rand(1, 3);
|
||||
return $bar;
|
||||
}
|
||||
|
||||
switch(foo()) {
|
||||
case 1: break;
|
||||
case 2: break;
|
||||
case 3: break;
|
||||
default:
|
||||
echo "bar";
|
||||
}',
|
||||
'error_message' => 'ParadoxicalCondition'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user