psalm / psalm-plugin-laravel

A Psalm plugin for Laravel
MIT License
307 stars 72 forks source link

Could not get class storage for eloquent #145

Closed giraz82 closed 3 years ago

giraz82 commented 3 years ago

Describe the bug Running Psalm with --debug-by-line on a Laravel 8 project I get:

 /var/www/html/app/Models/User.php:1

   Exception

  Could not get class storage for eloquent
Stack trace in the forked worker:
#0 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(750): Psalm\Internal\Provider\ClassLikeStorageProvider->get('Eloquent')
#1 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(394): Psalm\Internal\Analyzer\ClassAnalyzer::addContextProperties(Object(Psalm\Internal\Analyzer\ClassAnalyzer), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Context), 'App\\Models\\Mapp...', 'Illuminate\\Data...', Array)
#2 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(213): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#3 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(343): Psalm\Internal\Analyzer\FileAnalyzer->analyze(NULL)
#4 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(193): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(5, '/var/www/html/a...')
#5 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(409): Psalm\Internal\Fork\Pool->__construct(Array, Object(Closure), Object(Closure), Object(Closure), Object(Closure))
#6 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(272): Psalm\Internal\Codebase\Analyzer->doAnalysis(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 5)
#7 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(636): Psalm\Internal\Codebase\Analyzer->analyzeFiles(Object(Psalm\Internal\Analyzer\ProjectAnalyzer), 5, false, true)
#8 /var/www/html/vendor/vimeo/psalm/src/psalm.php(700): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/var/www/html/', true)
#9 /var/www/html/vendor/vimeo/psalm/src/psalm.php(884): Psalm\{closure}(Array)
#10 /var/www/html/vendor/vimeo/psalm/psalm(2): require_once('/var/www/html/v...')
#11 {main}

Ofc I have the issue also without --debug-by-line.

Impacted Versions

barryvdh/laravel-debugbar                      v3.5.7                           
barryvdh/laravel-ide-helper                    v2.9.1                           
fruitcake/laravel-cors                         v2.0.4                        
laravel/framework                              v8.44.0                          
laravel/sail                                   v1.7.0                          
laravel/tinker                                 v2.6.1                           
psalm/plugin-laravel                           v1.4.5                         
spatie/laravel-ray                             1.18.0                           
vimeo/psalm                                    4.7.3                           

Additional context User.php is the standard user class that comes with every fresh new project.

I tried to remove psalm and psalm/plugin-laravel, clear the cache, and I get the same Could not get class storage for eloquent in other parts of the codebase, for example

/var/www/html/tests/Feature/Models/Mapper/v1/TestCase.php:1

I'm stuck with this.

Edit: I forgot to mention that I'm on php 8.0.3

Ilyes512 commented 3 years ago

I get a similar error except for illuminate\foundation\application. It might be related so I decided to add it here instead of creating a new issue (I hope that is okey)

./vendor/bin/psalm --debug-by-line

...<large part left out>

Have populated Signet\DataContainer\DataContainerException
Have populated Symfony\Component\Console\Exception\InvalidOptionException
Have populated Symfony\Component\Console\Helper\TableStyle
Have populated Symfony\Component\Console\Helper\TableRows
Have populated Symfony\Component\Console\Helper\TableCell
Have populated Symfony\Component\Console\Helper\TableSeparator
Have populated Symfony\Component\Console\Helper\ProgressBar
Have populated Signet\DataContainer\Util
Have populated Symfony\Component\Console\Helper\TableCellStyle
ClassLikeStorage is populated
FileStorage is populating
FileStorage is populated
Registering stub files
Parsing /workspace/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub
Deep scanning /workspace/vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub
Parsing /workspace/vendor/vimeo/psalm/stubs/CoreGenericClasses.phpstub
Deep scanning /workspace/vendor/vimeo/psalm/stubs/CoreGenericClasses.phpstub
Uncaught InvalidArgumentException: Could not get class storage for illuminate\foundation\application in /workspace/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:42
Stack trace:
#0 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php(196): Psalm\Internal\Provider\ClassLikeStorageProvider->get('illuminate\\foun...')
#1 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php(182): Psalm\Internal\PhpVisitor\Reflector\ClassLikeNodeScanner->start(Object(PhpParser\Node\Stmt\Interface_))
#2 /workspace/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(200): Psalm\Internal\PhpVisitor\ReflectorVisitor->enterNode(Object(PhpParser\Node\Stmt\Interface_))
#3 /workspace/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(91): PhpParser\NodeTraverser->traverseArray(Array)
#4 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/Scanner/FileScanner.php(86): PhpParser\NodeTraverser->traverse(Array)
#5 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php(577): Psalm\Internal\Scanner\FileScanner->scan(Object(Psalm\Codebase), Object(Psalm\Storage\FileStorage), true, Object(Psalm\Progress\DebugProgress))
#6 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php(328): Psalm\Internal\Codebase\Scanner->scanFile('/workspace/vend...', Array, true)
#7 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php(447): Psalm\Internal\Codebase\Scanner->Psalm\Internal\Codebase\{closure}(1, '/workspace/vend...')
#8 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Scanner.php(292): Psalm\Internal\Codebase\Scanner->scanFilePaths(1)
#9 /workspace/vendor/vimeo/psalm/src/Psalm/Codebase.php(471): Psalm\Internal\Codebase\Scanner->scanFiles(Object(Psalm\Internal\Codebase\ClassLikes), 1)
#10 /workspace/vendor/vimeo/psalm/src/Psalm/Config.php(1834): Psalm\Codebase->scanFiles()
#11 /workspace/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(623): Psalm\Config->visitStubFiles(Object(Psalm\Codebase), Object(Psalm\Progress\DebugProgress))
#12 /workspace/vendor/vimeo/psalm/src/psalm.php(700): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/workspace/', true)
#13 /workspace/vendor/vimeo/psalm/src/psalm.php(884): Psalm\{closure}(Array)
#14 /workspace/vendor/vimeo/psalm/psalm(2): require_once('/workspace/vend...')
#15 {main}
(Psalm 4.7.3@38c452ae584467e939d55377aaf83b5a26f19dd1 crashed due to an uncaught Throwable)

Using php version 8.0.7:

barryvdh/laravel-ide-helper                    v2.9.1    Laravel IDE Helper, generates correct PHPDocs for all Fac...
laravel/framework                              v8.46.0   The Laravel Framework.
laravel/tinker                                 v2.6.1    Powerful REPL for the Laravel framework.
php-standard-library/psalm-plugin              1.1.1     Psalm plugin for the PHP Standard Library
psalm/plugin-laravel                           v1.4.7    A Laravel plugin for Psalm
psalm/plugin-mockery                           0.7.0     Psalm plugin for Mockery
psalm/plugin-phpunit                           0.16.0    Psalm plugin for PHPUnit
vimeo/psalm                                    4.7.3     A static analysis tool for finding errors in PHP applicat...

I am using this in a Laravel library using orchestral/testbench.

mr-feek commented 3 years ago

@Ilyes512 I may have just resolved your issue with https://github.com/psalm/psalm-plugin-laravel/pull/152 -- but if not, can you please open a new ticket? It's a bit different than this issue

mr-feek commented 3 years ago

@giraz82 could you please share some code that is triggering the issue? For example, what is referencing Eloquent ?

caugner commented 3 years ago

I'm experiencing similar issues recently, and it just popped up again:

Scanning files...

   InvalidArgumentException 

  Could not get class storage for illuminate\support\facades\ratelimiter

  at vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:42
     38▕     public function get(string $fq_classlike_name): ClassLikeStorage
     39▕     {
     40▕         $fq_classlike_name_lc = strtolower($fq_classlike_name);
     41▕         if (!isset(self::$storage[$fq_classlike_name_lc])) {
  ➜  42▕             throw new \InvalidArgumentException('Could not get class storage for ' . $fq_classlike_name_lc);
     43▕         }
     44▕ 
     45▕         return self::$storage[$fq_classlike_name_lc];
     46▕     }

Clearing the cache with psalm --clear-cache solves the issue.

mr-feek commented 3 years ago

could you please share some code to reproduce @caugner

giraz82 commented 3 years ago

@giraz82 could you please share some code that is triggering the issue? For example, what is referencing Eloquent ?

@mr-feek in my case, it's just the standard User class that comes with Laravel:

<?php declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

/**
 * Class User.
 */
final class User extends Authenticatable
{
    use HasFactory;
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Nothing special as you can see. But I think that the behaviour is quite random and not related to a specific class nor block of code. I launched again psalm in this project (I needed to comment out it to proceed in my project) and now I'm getting the same error but on a different place:

...
Forking analysis
Getting /var/www/html/app/Providers/EventServiceProvider.php
Analyzing /var/www/html/app/Providers/EventServiceProvider.php
/var/www/html/app/Providers/EventServiceProvider.php:1
/var/www/html/app/Http/Middleware/Authenticate.php:22

   Exception

  Could not get class storage for eloquent
Stack trace in the forked worker:
#0 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(750): Psalm\Internal\Provider\ClassLikeStorageProvider->get('Eloquent')
#1 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ClassAnalyzer.php(394): Psalm\Internal\Analyzer\ClassAnalyzer::addContextProperties(Object(Psalm\Internal\Analyzer\ClassAnalyzer), Object(Psalm\Storage\ClassLikeStorage), Object(Psalm\Context), 'App\\Models\\Soap...', 'Illuminate\\Data...', Array)
#2 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/FileAnalyzer.php(213): Psalm\Internal\Analyzer\ClassAnalyzer->analyze(Object(Psalm\Context), Object(Psalm\Context))
#3 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/Analyzer.php(343): Psalm\Internal\Analyzer\FileAnalyzer->analyze(NULL)
#4 /var/www/html/vendor/vimeo/psalm/src/Psalm/Internal/Fork/Pool.php(193): Psalm\Internal\Codebase\Analyzer->Psalm\Internal\Codebase\{closure}(0, '/var/www/html/a...')
...

Also here Authenitcate middleware is the Laravel standard one:

<?php declare(strict_types=1);

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;

/**
 * Class Authenticate.
 */
final class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     *
     * @param Request $request
     *
     * @return string|null
     */
    protected function redirectTo($request): ?string
    {
        if (!$request->expectsJson()) {
            return route('login');
        }

        return null;
    }
}

Let me know if you need further info.

caugner commented 3 years ago

Here's another one:

Parsing /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Concerns/SupportsDefaultModels.php
Deep scanning /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Concerns/SupportsDefaultModels.php
Parsing /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php
Deep scanning /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php
Parsing /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
Deep scanning /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php

   InvalidArgumentException 

  Could not get class storage for illuminate\support\facades\paralleltesting

  at vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:42
     38▕     public function get(string $fq_classlike_name): ClassLikeStorage
     39▕     {
     40▕         $fq_classlike_name_lc = strtolower($fq_classlike_name);
     41▕         if (!isset(self::$storage[$fq_classlike_name_lc])) {
  ➜  42▕             throw new \InvalidArgumentException('Could not get class storage for ' . $fq_classlike_name_lc);
     43▕         }
     44▕ 
     45▕         return self::$storage[$fq_classlike_name_lc];
     46▕     }

Running it again yielded the same error.

mr-feek commented 3 years ago

Hm, maybe ill just search for all classes within the facades namespace and force psalm to scan them until I figure out what's wrong with the upstream psalm cache..

mr-feek commented 3 years ago

Opened https://github.com/vimeo/psalm/issues/5971 upstream

mr-feek commented 3 years ago

I think https://github.com/psalm/psalm-plugin-laravel/commit/b287a0ad17f5086eb40fbc1c481768fe24588950 should help resolve these issues.

mr-feek commented 3 years ago

I'm going to close this -- please open a new ticket with code to reproduce if you run into any more issues

caugner commented 3 years ago

@mr-feek Will you release a new minor version soon? I will test and report back then, because our Psalm runs fail consistently.

mr-feek commented 3 years ago

@caugner in the mean time try using dev-master! Or else invoke CI with --no-cache. I'm hoping to have a new minor version out in the next week or so.

caugner commented 3 years ago

@mr-feek FYI I'm still experiencing the same issue with da4e6bc:

$ composer show | grep -E 'psalm|laravel'
andrey-helldar/laravel-lang-publisher v10.0.4            Publisher lang files for the Laravel Framework, Jetstream, Fortify, Cashier, Spark and Nova from Laravel-Lang/lang
andrey-helldar/laravel-support        v2.0.1             Various helper files for the Laravel and Lumen frameworks
barryvdh/laravel-ide-helper           v2.9.1             Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.
beyondcode/laravel-dump-server        1.7.0              Symfony Var-Dump Server for Laravel
fruitcake/laravel-cors                v2.0.4             Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application
laravel-lang/lang                     10.0.2             Languages for Laravel
laravel/framework                     v8.49.0            The Laravel Framework.
laravel/sail                          v1.8.3             Docker files for running a basic Laravel application.
laravel/sanctum                       v2.11.2            Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.
laravel/tinker                        v2.6.1             Powerful REPL for the Laravel framework.
laravel/ui                            v3.3.0             Laravel UI utilities and presets.
psalm/plugin-laravel                  dev-master da4e6bc A Laravel plugin for Psalm
sentry/sentry-laravel                 2.7.0              Laravel SDK for Sentry (https://sentry.io)
spatie/laravel-ray                    1.17.4             Easily debug Laravel apps
vimeo/psalm                           4.8.1              A static analysis tool for finding errors in PHP applications
$ vendor/bin/psalm
Scanning files...

   InvalidArgumentException 

  Could not get class storage for illuminate\support\facades\ratelimiter

  at vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:43
     39▕     public function get(string $fq_classlike_name): ClassLikeStorage
     40▕     {
     41▕         $fq_classlike_name_lc = strtolower($fq_classlike_name);
     42▕         if (!isset(self::$storage[$fq_classlike_name_lc])) {
  ➜  43▕             throw new \InvalidArgumentException('Could not get class storage for ' . $fq_classlike_name_lc);
     44▕         }
     45▕ 
     46▕         return self::$storage[$fq_classlike_name_lc];
     47▕     }
mr-feek commented 3 years ago

I'm afraid I can't really help without a reproducer -- I haven't run into this specific issue at all

caugner commented 3 years ago

Alright, I will run Psalm directly via PhpStorm from now on, with Xdebug enabled and a breakpoint set in that line 43. Hopefully I can reproduce the issue with that setup, so that I can dig a bit in the debug state to see what's going on and why the class is missing in the storage.

kiwina commented 3 years ago

Not sure that running it over PhpStorm will help. I'm seeing Could not get class storage for illuminate\support\facades\paralleltesting as well on a pretty much fresh setup

giraz82 commented 2 years ago

I still have the error appearing randomly in a new Laravel project that was working fine until today:

Could not get class storage for eloquent

  at vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:43
     39▕     public function get(string $fq_classlike_name): ClassLikeStorage
     40▕     {
     41▕         $fq_classlike_name_lc = strtolower($fq_classlike_name);
     42▕         if (!isset(self::$storage[$fq_classlike_name_lc])) {
  ➜  43▕             throw new \InvalidArgumentException('Could not get class storage for ' . $fq_classlike_name_lc);
     44▕         }
     45▕ 
     46▕         return self::$storage[$fq_classlike_name_lc];
     47▕     }

I'm using

"psalm/plugin-laravel": "1.5.1",
"vimeo/psalm": "4.13.1"

But also updating psalm to 4.14.0 makes any difference.

Any idea?