1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 12:24:49 +01:00

Skip conditional includes when registering autoload files (#4967)

This should allow analysis of forward-compatible polyfills used in
codebases targeting older PHP versions.

The following previously problematic polyfills should now emit no parse
errors:

* `symfony/polyfill-ctype`
* `symfony/polyfill-intl-grapheme`
* `symfony/polyfill-intl-normalizer`
* `symfony/polyfill-mbstring`

The pattern that is now works as intended looks like this:
```php
if (\PHP_VERSION_ID >= 80000) {
    require __DIR__ . '/bootstrap80.php';
    return;
}
```

Previously Psalm would scan the required file even when codebase
targeted older PHP versions, and would emit parse errors when that file
contained PHP 8 syntax.

Fixes #4961 and #4965
This commit is contained in:
Bruce Weirdan 2021-01-09 23:14:58 +02:00 committed by Daniil Gentili
parent d9999b575d
commit 9ce329c866
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
2 changed files with 38 additions and 1 deletions

View File

@ -6,6 +6,10 @@ use function function_exists;
use function implode;
use function interface_exists;
use PhpParser;
use PhpParser\ConstExprEvaluationException;
use PhpParser\ConstExprEvaluator;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ConstFetch;
use Psalm\Aliases;
use Psalm\Codebase;
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
@ -236,6 +240,39 @@ class ExpressionResolver
return $enter_conditional_left !== false || $enter_conditional_right !== false;
}
if ($codebase->register_autoload_files) {
if ((
$expr instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual
|| $expr instanceof PhpParser\Node\Expr\BinaryOp\Greater
|| $expr instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual
|| $expr instanceof PhpParser\Node\Expr\BinaryOp\Smaller
) && (
(
$expr->left instanceof PhpParser\Node\Expr\ConstFetch
&& $expr->left->name->parts === ['PHP_VERSION_ID']
&& $expr->right instanceof PhpParser\Node\Scalar\LNumber
) || (
$expr->right instanceof PhpParser\Node\Expr\ConstFetch
&& $expr->right->name->parts === ['PHP_VERSION_ID']
&& $expr->left instanceof PhpParser\Node\Scalar\LNumber
)
)
) {
$php_version_id = $codebase->php_major_version * 10000 + $codebase->php_minor_version * 100;
$evaluator = new ConstExprEvaluator(function (Expr $expr) use ($php_version_id) {
if ($expr instanceof ConstFetch && $expr->name->parts === ['PHP_VERSION_ID']) {
return $php_version_id;
}
throw new ConstExprEvaluationException('unexpected');
});
try {
return (bool) $evaluator->evaluateSilently($expr);
} catch (ConstExprEvaluationException $e) {
return null;
}
}
}
if (!$expr instanceof PhpParser\Node\Expr\FuncCall) {
return null;
}

View File

@ -38,7 +38,7 @@ class ExpressionScanner
?FunctionLikeStorage $functionlike_storage,
?int $skip_if_descendants
) : void {
if ($node instanceof PhpParser\Node\Expr\Include_) {
if ($node instanceof PhpParser\Node\Expr\Include_ && !$skip_if_descendants) {
self::visitInclude(
$codebase,
$file_storage,