1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-16 03:17:02 +01:00
psalm/src/Psalm/Checker/Statements/Block/TryChecker.php

91 lines
3.1 KiB
PHP
Raw Normal View History

2016-10-22 23:35:59 +02:00
<?php
namespace Psalm\Checker\Statements\Block;
use PhpParser;
use Psalm\Checker\ClassLikeChecker;
use Psalm\Checker\ScopeChecker;
use Psalm\Checker\StatementsChecker;
2016-11-02 07:29:00 +01:00
use Psalm\Context;
2016-10-22 23:35:59 +02:00
use Psalm\Type;
class TryChecker
{
/**
2016-11-02 07:29:00 +01:00
* @param StatementsChecker $statements_checker
* @param PhpParser\Node\Stmt\TryCatch $stmt
* @param Context $context
* @param Context|null $loop_context
* @return false|null
2016-10-22 23:35:59 +02:00
*/
2016-11-02 07:29:00 +01:00
public static function check(
StatementsChecker $statements_checker,
PhpParser\Node\Stmt\TryCatch $stmt,
Context $context,
Context $loop_context = null
) {
2016-10-22 23:35:59 +02:00
$statements_checker->check($stmt->stmts, $context, $loop_context);
// clone context for catches after running the try block, as
// we optimistically assume it only failed at the very end
$original_context = clone $context;
foreach ($stmt->catches as $catch) {
$catch_context = clone $original_context;
$catch_class = ClassLikeChecker::getAbsoluteClassFromName(
$catch->type,
$statements_checker->getNamespace(),
$statements_checker->getAliasedClasses()
);
if ($context->check_classes) {
$absolute_class = $catch_class;
if (ClassLikeChecker::checkAbsoluteClassOrInterface(
$absolute_class,
$statements_checker->getCheckedFileName(),
$stmt->getLine(),
$statements_checker->getSuppressedIssues()
2016-11-02 07:29:00 +01:00
) === false) {
2016-10-22 23:35:59 +02:00
return false;
}
}
$catch_context->vars_in_scope['$' . $catch->var] = new Type\Union([
new Type\Atomic($catch_class)
]);
$catch_context->vars_possibly_in_scope['$' . $catch->var] = true;
$statements_checker->registerVariable('$' . $catch->var, $catch->getLine());
$statements_checker->check($catch->stmts, $catch_context, $loop_context);
if (!ScopeChecker::doesAlwaysReturnOrThrow($catch->stmts)) {
foreach ($catch_context->vars_in_scope as $catch_var => $type) {
2016-11-02 07:29:00 +01:00
if ($catch->var !== $catch_var &&
isset($context->vars_in_scope[$catch_var]) &&
(string) $context->vars_in_scope[$catch_var] !== (string) $type
) {
$context->vars_in_scope[$catch_var] = Type::combineUnionTypes(
$context->vars_in_scope[$catch_var],
$type
);
2016-10-22 23:35:59 +02:00
}
}
2016-11-02 07:29:00 +01:00
$context->vars_possibly_in_scope = array_merge(
$catch_context->vars_possibly_in_scope,
$context->vars_possibly_in_scope
);
2016-10-22 23:35:59 +02:00
}
}
if ($stmt->finallyStmts) {
$statements_checker->check($stmt->finallyStmts, $context, $loop_context);
}
2016-11-02 07:29:00 +01:00
return null;
2016-10-22 23:35:59 +02:00
}
}