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

125 lines
4.4 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;
use Psalm\CodeLocation;
2016-11-02 07:29:00 +01:00
use Psalm\Context;
2016-10-22 23:35:59 +02:00
use Psalm\Type;
use Psalm\Type\Atomic\TNamedObject;
2016-10-22 23:35:59 +02:00
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
2017-05-27 02:16:18 +02:00
*
2016-11-02 07:29:00 +01:00
* @return false|null
2016-10-22 23:35:59 +02:00
*/
public static function analyze(
2016-11-02 07:29:00 +01:00
StatementsChecker $statements_checker,
PhpParser\Node\Stmt\TryCatch $stmt,
Context $context,
Context $loop_context = null
) {
$statements_checker->analyze($stmt->stmts, $context, $loop_context);
2016-10-22 23:35:59 +02:00
// 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;
$fq_catch_classes = [];
2016-10-22 23:35:59 +02:00
foreach ($catch->types as $catch_type) {
2016-12-08 23:15:51 +01:00
$fq_catch_class = ClassLikeChecker::getFQCLNFromNameObject(
$catch_type,
Refactor scanning and analysis, introducing multithreading (#191) * Add failing test * Add visitor to soup up classlike references * Move a whole bunch of code into the visitor * Move some methods back, move onto analysis stage * Use the getAliases method everywhere * Fix refs * Fix more refs * Fix some tests * Fix more tests * Fix include tests * Shift config class finding to project checker and fix bugs * Fix a few more tests * transition test to new syntax * Remove var_dump * Delete a bunch of code and fix mutation test * Remove unnecessary visitation * Transition to better mocked out file provider, breaking some cached statement loading * Use different scheme for naming anonymous classes * Fix anonymous class issues * Refactor file/statement loading * Add specific property types * Fix mapped property assignment * Improve how we deal with traits * Fix trait checking * Pass Psalm checks * Add multi-process support * Delay console output until the end * Remove PHP 7 syntax * Update file storage with classes * Fix scanning individual files and add reflection return types * Always turn XDebug off * Add quicker method of getting method mutations * Queue return types for crawling * Interpret all strings as possible classes once we see a `get_class` call * Check invalid return types again * Fix template namespacing issues * Default to class-insensitive file names for includes * Don’t overwrite existing issues data * Add var docblocks for scanning * Add null check * Fix loading of external classes in templates * Only try to populate class when we haven’t yet seen it’s not a class * Fix trait property accessibility * Only ever improve docblock param type * Make param replacement more robust * Fix static const missing inferred type * Fix a few more tests * Register constant definitions * Fix trait aliasing * Skip constant type tests for now * Fix linting issues * Make sure caching is off for tests * Remove unnecessary return * Use emulative parser if on PHP 5.6 * Cache parser for faster first-time parse * Fix constant resolution when scanning classes * Remove test that’s beyond a practical scope * Add back --diff support * Add --help for --threads * Remove unused vars
2017-07-25 22:11:02 +02:00
$statements_checker->getAliases()
);
2016-10-22 23:35:59 +02:00
2016-12-08 23:15:51 +01:00
if ($context->check_classes) {
if (ClassLikeChecker::checkFullyQualifiedClassLikeName(
$statements_checker->getFileChecker()->project_checker,
$fq_catch_class,
new CodeLocation($statements_checker->getSource(), $catch_type, $context->include_location),
$statements_checker->getSuppressedIssues()
) === false) {
return false;
}
2016-10-22 23:35:59 +02:00
}
2016-12-08 23:15:51 +01:00
$fq_catch_classes[] = $fq_catch_class;
2016-10-22 23:35:59 +02:00
}
$catch_var_id = '$' . $catch->var;
$catch_context->vars_in_scope[$catch_var_id] = new Type\Union(
array_map(
2016-12-07 01:41:52 +01:00
/**
* @param string $fq_catch_class
2017-05-27 02:16:18 +02:00
*
2016-12-07 20:13:39 +01:00
* @return Type\Atomic
2016-12-07 01:41:52 +01:00
*/
function ($fq_catch_class) {
return new TNamedObject($fq_catch_class);
},
$fq_catch_classes
)
);
2016-10-22 23:35:59 +02:00
// discard all clauses because crazy stuff may have happened in try block
$catch_context->clauses = [];
$catch_context->vars_possibly_in_scope[$catch_var_id] = true;
if (!$statements_checker->hasVariable($catch_var_id)) {
$statements_checker->registerVariable(
$catch_var_id,
new CodeLocation($statements_checker, $catch, $context->include_location, true)
);
}
2016-10-22 23:35:59 +02:00
// this registers the variable to avoid unfair deadcode issues
$catch_context->hasVariable($catch_var_id);
2016-10-22 23:35:59 +02:00
$statements_checker->analyze($catch->stmts, $catch_context, $loop_context);
2016-10-22 23:35:59 +02:00
$context->referenced_var_ids = array_merge(
$catch_context->referenced_var_ids,
$context->referenced_var_ids
);
2017-02-02 06:45:23 +01:00
if (ScopeChecker::getFinalControlActions($catch->stmts) !== [ScopeChecker::ACTION_END]) {
2016-10-22 23:35:59 +02:00
foreach ($catch_context->vars_in_scope as $catch_var => $type) {
2016-11-02 07:29:00 +01:00
if ($catch->var !== $catch_var &&
$context->hasVariable($catch_var) &&
2016-11-02 07:29:00 +01:00
(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->finally) {
$statements_checker->analyze($stmt->finally->stmts, $context, $loop_context);
2016-10-22 23:35:59 +02:00
}
2016-11-02 07:29:00 +01:00
return null;
2016-10-22 23:35:59 +02:00
}
}