Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could not get class storage for google_service in #4419

Closed
arjenm opened this issue Oct 26, 2020 · 3 comments
Closed

Could not get class storage for google_service in #4419

arjenm opened this issue Oct 26, 2020 · 3 comments

Comments

@arjenm
Copy link

arjenm commented Oct 26, 2020

Psalm 3.18.2 fails on this construction in Google:

$classMap = [
    'Google\\Client' => 'Google_Client',
    'Google\\Service' => 'Google_Service',
    'Google\\AccessToken\\Revoke' => 'Google_AccessToken_Revoke',
    'Google\\AccessToken\\Verify' => 'Google_AccessToken_Verify',
    'Google\\Model' => 'Google_Model',
    'Google\\Utils\\UriTemplate' => 'Google_Utils_UriTemplate',
    'Google\\AuthHandler\\Guzzle6AuthHandler' => 'Google_AuthHandler_Guzzle6AuthHandler',
    'Google\\AuthHandler\\Guzzle7AuthHandler' => 'Google_AuthHandler_Guzzle7AuthHandler',
    'Google\\AuthHandler\\Guzzle5AuthHandler' => 'Google_AuthHandler_Guzzle5AuthHandler',
    'Google\\AuthHandler\\AuthHandlerFactory' => 'Google_AuthHandler_AuthHandlerFactory',
    'Google\\Http\\Batch' => 'Google_Http_Batch',
    'Google\\Http\\MediaFileUpload' => 'Google_Http_MediaFileUpload',
    'Google\\Http\\REST' => 'Google_Http_REST',
    'Google\\Task\\Retryable' => 'Google_Task_Retryable',
    'Google\\Task\\Exception' => 'Google_Task_Exception',
    'Google\\Task\\Runner' => 'Google_Task_Runner',
    'Google\\Collection' => 'Google_Collection',
    'Google\\Service\\Exception' => 'Google_Service_Exception',
    'Google\\Service\\Resource' => 'Google_Service_Resource',
    'Google\\Exception' => 'Google_Exception',
];

foreach ($classMap as $class => $alias) {
    class_alias($class, $alias);
}

From: https://github.com/googleapis/google-api-php-client/blob/master/src/aliases.php

Apparently, they decided to move to PSR-code, but their auto-generated stuff still refers to Google_Service:
https://github.com/googleapis/google-api-php-client-services/tree/master/src/Google/Service

It trips up Psalm with this error:

Uncaught InvalidArgumentException: Could not get class storage for google_service in /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:42
Stack trace:
#0 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php(95): Psalm\Internal\Provider\ClassLikeStorageProvider->get('Google_Service')
#1 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(148): Psalm\Internal\Analyzer\Statements\Expression\Call\StaticCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\StaticCall), Object(Psalm\Context))
#2 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(39): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\StaticCall), Object(Psalm\Context), false, NULL, true)
#3 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(500): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\StaticCall), Object(Psalm\Context), false, NULL, true)
#4 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(173): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), NULL)
#5 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(606): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), NULL, true)
#6 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php(128): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), NULL, true)
#7 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(437): Psalm\Internal\Analyzer\ClassLikeAnalyzer->getMethodMutations('__construct', Object(Psalm\Context))
#8 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(1393): Psalm\Internal\Analyzer\FileAnalyzer->getMethodMutations(Object(Psalm\Internal\MethodIdentifier), Object(Psalm\Context), true)
#9 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(404): Psalm\Internal\Analyzer\ProjectAnalyzer->getMethodMutations(Object(Psalm\Internal\MethodIdentifier), Object(Psalm\Context), '/project...', 'src/Pricewatch/...')
#10 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/Expression/Call/StaticCallAnalyzer.php(815): Psalm\Internal\Analyzer\FileAnalyzer->getMethodMutations(Object(Psalm\Internal\MethodIdentifier), Object(Psalm\Context))
#11 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(148): Psalm\Internal\Analyzer\Statements\Expression\Call\StaticCallAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\StaticCall), Object(Psalm\Context))
#12 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/Statements/ExpressionAnalyzer.php(39): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::handleExpression(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\StaticCall), Object(Psalm\Context), false, Object(Psalm\Context), true)
#13 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(500): Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer::analyze(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Expr\StaticCall), Object(Psalm\Context), false, Object(Psalm\Context), true)
#14 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php(173): Psalm\Internal\Analyzer\StatementsAnalyzer::analyzeStatement(Object(Psalm\Internal\Analyzer\StatementsAnalyzer), Object(PhpParser\Node\Stmt\Expression), Object(Psalm\Context), Object(Psalm\Context))
#15 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php(606): Psalm\Internal\Analyzer\StatementsAnalyzer->analyze(Array, Object(Psalm\Context), Object(Psalm\Context), true)
#16 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(1382): Psalm\Internal\Analyzer\FunctionLikeAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Internal\Provider\NodeDataProvider), Object(Psalm\Context), true)
#17 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(837): Psalm\Internal\Analyzer\ClassAnalyzer->checkPropertyInitialization(Object(Psalm\Codebase), Object(Psalm\Config), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Context), Object(Psalm\Context), Object(Psalm\Internal\Analyzer\MethodAnalyzer))
#18 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(215): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#19 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(338): Psalm\Internal\Analyzer\FileAnalyzer->analyze(NULL)
#20 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(578): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(2424, '/project...')
#21 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(270): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1)
#22 /project/website/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(639): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 1, false, true)
#23 /project/website/vendor/vimeo/psalm/src/psalm.php(675): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/project...', false)
#24 /project/website/vendor/vimeo/psalm/psalm(2): require_once('/project...')
#25 {main}
(Psalm 3.18.2@19aa905f7c3c7350569999a93c40ae91ae4e1626 crashed due to an uncaught Throwable)
@muglug
Copy link
Collaborator

muglug commented Oct 26, 2020

Does the error also appear with --no-cache?

@arjenm
Copy link
Author

arjenm commented Oct 27, 2020

@muglug yes it does fail with or without a pre-existing cache and/or with the --no-cache flag.

I now have a workaround; a separate psalm autoload file that simply has an unrolled version of that loop in a block that never gets executed:

if (false) {
    class_alias('Google\\Client', 'Google_Client');
    class_alias('Google\\Service', 'Google_Service');
    class_alias('Google\\AccessToken\\Revoke', 'Google_AccessToken_Revoke');
    // etc
}

Those class_alias-calls from the aliases.php are loaded via composer's autoload file. But I assume the code in src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php:953 which will do some important work with the explicit class_alias-calls doesn't work with loops like that.

Perhaps you could work around having to statically parse class_alias, by doing a fall-back lookup in the ClassLikeStorageProvider::get. I.e. if there is no storage, but the class does exist, its likely an alias.
The original class name can be fetched using a new ReflectionClass and reading its name-property.

I'm not sufficiently familiar with Psalm to know whether there are similar places where the original class of an alias is needed.

@weirdan
Copy link
Collaborator

weirdan commented Dec 3, 2022

Closing as stale, this was either fixed or reported again against a newer version.

@weirdan weirdan closed this as completed Dec 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants