psalm
psalm copied to clipboard
4.25.0 Regression: Could not get class storage for resourcebundle for PHP < 8.0
When I run --alter: EDIT: seems to be there without --alter too
php /opt/composer/vendor/bin/psalm --config=my-rules.xml --alter --plugin=vendor/orklah/psalm-strict-equality/src/Plugin.php --php-version=7.4 my-file.php
When I do --php-version=8.0 or --php-version=8.1 I don't get an error. For everythint <= 7.4 I get this error.
Uncaught InvalidArgumentException: Could not get class storage for resourcebundle in /path/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:46
Stack trace:
#0 /path/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeExpander.php(607): Psalm\Internal\Provider\ClassLikeStorageProvider->get('ResourceBundle')
#1 /path/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeExpander.php(178): Psalm\Internal\Type\TypeExpander::expandNamedObject(Object(Psalm\Codebase), Object(Psalm\Type\Atomic\TNamedObject), NULL, NULL, NULL, false, true)
#2 /path/vendor/vimeo/psalm/src/Psalm/Internal/Type/TypeExpander.php(82): Psalm\Internal\Type\TypeExpander::expandAtomic(Object(Psalm\Codebase), Object(Psalm\Type\Atomic\TNamedObject), NULL, NULL, NULL, true, false, false, true, false)
#3 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php(284): Psalm\Internal\Type\TypeExpander::expandUnion(Object(Psalm\Codebase), Object(Psalm\Type\Union), NULL, NULL, NULL, true, false, false, true)
#4 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentAnalyzer.php(195): Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentAnalyzer::checkFunctionLikeTypeMatches(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(Psalm\Codebase), 'count', NULL, NULL, NULL, Object(Psalm\CodeLocation), Object(Psalm\Storage\FunctionLikeParameter), true, Object(Psalm\Type\Union), 0, 0, Object(PhpParser\Node\Arg), Object(Psalm\Context), Array, NULL, true, true)
#5 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/ArgumentsAnalyzer.php(828): Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentAnalyzer::checkArgumentMatches(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), 'count', NULL, NULL, NULL, Object(Psalm\CodeLocation), Object(Psalm\Storage\FunctionLikeParameter), 0, 0, true, Object(PhpParser\Node\Arg), Object(Psalm\Type\Union), Object(Psalm\Context), Array, NULL, true, true)
#6 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php(214): Psalm\Internal\Analyzer\Statements\Expression\Call\ArgumentsAnalyzer::checkArgumentsMatch(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Array, 'count', Array, NULL, NULL, Object(Psalm\Internal\Type\TemplateResult), Object(Psalm\CodeLocation), Object(Psalm\Context))
#7 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(296): Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context))
#8 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(78): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context), false, NULL, false)
#9 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOpAnalyzer.php(120): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\FuncCall), Object(Psalm\Context))
#10 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(266): Psalm\Internal\Analyzer\Statements\Expression\BinaryOpAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Identical), Object(Psalm\Context), 0, false)
#11 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(78): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Identical), Object(Psalm\Context), false, NULL, false)
#12 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfConditionalAnalyzer.php(117): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Identical), Object(Psalm\Context))
#13 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElseAnalyzer.php(107): Psalm\Internal\Analyzer\Statements\Block\IfConditionalAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\BinaryOp\Identical), Object(Psalm\Context), Object(Psalm\Codebase), Object(Psalm\Internal\Scope\IfScope), 11411)
#14 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(518): Psalm\Internal\Analyzer\Statements\Block\IfElseAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context))
#15 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context), NULL)
#16 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/IfAnalyzer.php(68): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context))
#17 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElseAnalyzer.php(365): Psalm\Internal\Analyzer\Statements\Block\IfElse\IfAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Internal\Scope\IfScope), Object(Psalm\Internal\Scope\IfConditionalScope), Object(Psalm\Context), Object(Psalm\Context), Object(Psalm\Context), Array)
#18 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(518): Psalm\Internal\Analyzer\Statements\Block\IfElseAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context))
#19 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context), Object(Psalm\Context))
#20 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(476): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#21 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php(96): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#22 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(564): Psalm\Internal\Analyzer\FunctionAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Function_), Object(Psalm\Context))
#23 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Function_), Object(Psalm\Context), Object(Psalm\Context))
#24 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(205): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#25 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php(204): Psalm\Internal\Analyzer\FileAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#26 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(347): Psalm\Internal\Analyzer\Statements\Expression\IncludeAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Include_), Object(Psalm\Context), Object(Psalm\Context))
#27 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(78): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Include_), Object(Psalm\Context), false, Object(Psalm\Context), true)
#28 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(572): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Include_), Object(Psalm\Context), false, Object(Psalm\Context), true)
#29 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), Object(Psalm\Context))
#30 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(476): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#31 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php(96): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#32 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(564): Psalm\Internal\Analyzer\FunctionAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Function_), Object(Psalm\Context))
#33 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Function_), Object(Psalm\Context), NULL)
#34 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(205): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), NULL, true)
#35 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php(204): Psalm\Internal\Analyzer\FileAnalyzer->analyze(Object(Psalm\Context), NULL)
#36 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(347): Psalm\Internal\Analyzer\Statements\Expression\IncludeAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Include_), Object(Psalm\Context), NULL)
#37 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(78): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Include_), Object(Psalm\Context), false, NULL, true)
#38 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(572): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\Include_), Object(Psalm\Context), false, NULL, true)
#39 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), NULL)
#40 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElse/ElseIfAnalyzer.php(274): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context))
#41 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Block/IfElseAnalyzer.php(390): Psalm\Internal\Analyzer\Statements\Block\IfElse\ElseIfAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\ElseIf_), Object(Psalm\Internal\Scope\IfScope), Object(Psalm\Context), Object(Psalm\Context), Object(Psalm\Codebase), 63749)
#42 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(518): Psalm\Internal\Analyzer\Statements\Block\IfElseAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context))
#43 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\If_), Object(Psalm\Context), Object(Psalm\Context))
#44 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(476): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#45 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionAnalyzer.php(96): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context))
#46 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(564): Psalm\Internal\Analyzer\FunctionAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Function_), Object(Psalm\Context))
#47 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(207): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Function_), Object(Psalm\Context), NULL)
#48 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(205): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), NULL, true)
#49 /path/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(362): Psalm\Internal\Analyzer\FileAnalyzer->analyze()
#50 /path/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(619): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(0, '/path/to/my-file...')
#51 /path/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(291): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1)
#52 /path/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(1161): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1, true, false)
#53 /path/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalter.php(412): Psalm\Internal\Analyzer\ProjectAnalyzer->checkFile('/path/to/my-file...')
#54 /path/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php(931): Psalm\Internal\Cli\Psalter::run(Array)
#55 /path/vendor/vimeo/psalm/src/Psalm/Internal/Cli/Psalm.php(177): Psalm\Internal\Cli\Psalm::forwardCliCall(Array, Array)
#56 /path/vendor/vimeo/psalm/psalm(6): Psalm\Internal\Cli\Psalm::run(Array)
#57 /path/vendor/bin/psalm(115): include('/path/v...')
#58 {main}
(Psalm v4.25.0@d7cd84c4ebca74ba3419b9601f81d177bcbe2aac crashed due to an uncaught Throwable)
No
Are you using ResourceBundle somewhere in your code? Could you check if it's properly cased or not if you do?
Could you run with --debug-by-line and copy/paste the few lines surrounding the last location it shows?
Are you using ResourceBundle somewhere in your code?
No.
Could you run with --debug-by-line
Done. The last line before the "Uncaught:" is "some-of-my-files.php:288" If I check this file in my code base, this is the code there:
if ( count( $matches ) === 1 ) {
which is the "count" we see in initial stack trace #4 above. It seems the "count" triggers this issue, as I don't get the error when I remove all "count" from my file.
This PR: https://github.com/vimeo/psalm/pull/8217/files removed ResourceBundle from the list of types accepted in count starting from PHP8. It seems clearly related but I have no idea why Psalm would behave like that
In case it helps: the value of $matches in the count above is from $matches = preg_grep(
Could you push a PR that reverts that change: https://github.com/vimeo/psalm/pull/8217/files#diff-b8eaee1f550652657daf0a771be5e785bdb01e91acd004b4bbb4c41def706713R1546 and add a test?
I'm not sure why it would crash like that but it's not needed for anything, it shouldn't hurt to revert it
We upgraded to PHP8.1 bc of this bug. Added a PR for it now anyway for other people
For future reference, this is probably because ResourceBundle comes from the intl extension. I would guess if that extension were installed the crash would stop happening.
We should avoid referencing extension-declared classes in the callmap (except in the case where a function from an extension uses a class declared by the same extension).
Get similar error, but for predis\client
Could not get class storage for predis\client
at /docker/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:46
42▕ public function get(string $fq_classlike_name): ClassLikeStorage
43▕ {
44▕ $fq_classlike_name_lc = strtolower($fq_classlike_name);
45▕ if (!isset(self::$storage[$fq_classlike_name_lc])) {
➜ 46▕ throw new InvalidArgumentException('Could not get class storage for ' . $fq_classlike_name_lc);
47▕ }
48▕
49▕ return self::$storage[$fq_classlike_name_lc];
50▕ }