mirror of
https://github.com/barryvdh/laravel-ide-helper.git
synced 2026-08-22 12:03:08 +00:00
Keep imported phpstan/psalm types unqualified (#1797)
A type brought in with @phpstan-import-type is a local alias, not a class
in the model's namespace, but it was resolved as one:
@property-read \App\Models\ArrayShape $some_array
Collect the aliases declared with @phpstan-type/@psalm-type or imported
with @phpstan-import-type/@psalm-import-type on the model and its parents,
and return them as written.
Fixes #1773
This commit is contained in:
@@ -132,6 +132,10 @@ class ModelsCommand extends Command
|
|||||||
* @var array<string, Context>
|
* @var array<string, Context>
|
||||||
*/
|
*/
|
||||||
protected $contextCache = [];
|
protected $contextCache = [];
|
||||||
|
/**
|
||||||
|
* @var array<string, array<int, string>>
|
||||||
|
*/
|
||||||
|
protected $localTypeAliasCache = [];
|
||||||
/**
|
/**
|
||||||
* @var array<string, true>
|
* @var array<string, true>
|
||||||
*/
|
*/
|
||||||
@@ -1485,12 +1489,55 @@ class ModelsCommand extends Command
|
|||||||
return $typeAlias;
|
return $typeAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$localTypeAlias = strtok(trim($returnTag->getContent()), " \t\n\r");
|
||||||
|
|
||||||
|
if ($localTypeAlias !== false
|
||||||
|
&& in_array($localTypeAlias, $this->getLocalTypeAliases($reflection->getDeclaringClass()), true)
|
||||||
|
) {
|
||||||
|
return $localTypeAlias;
|
||||||
|
}
|
||||||
|
|
||||||
$type = $phpdoc->getTagsByName('return')[0]->getType();
|
$type = $phpdoc->getTagsByName('return')[0]->getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type aliases declared or imported on the given class and its parents.
|
||||||
|
*
|
||||||
|
* These are local names rather than classes, so they must be left as-is
|
||||||
|
* instead of being resolved against the class namespace.
|
||||||
|
*
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
protected function getLocalTypeAliases(ReflectionClass $class): array
|
||||||
|
{
|
||||||
|
$key = $class->getName();
|
||||||
|
|
||||||
|
if (isset($this->localTypeAliasCache[$key])) {
|
||||||
|
return $this->localTypeAliasCache[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
$aliases = [];
|
||||||
|
|
||||||
|
for ($current = $class; $current !== false; $current = $current->getParentClass()) {
|
||||||
|
if (($docComment = $current->getDocComment()) === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
preg_match_all(
|
||||||
|
'/@(?:phpstan|psalm)-(?:import-)?type\s+([A-Za-z_\x80-\xff][A-Za-z0-9_\x80-\xff]*)/',
|
||||||
|
$docComment,
|
||||||
|
$matches
|
||||||
|
);
|
||||||
|
|
||||||
|
$aliases = array_merge($aliases, $matches[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->localTypeAliasCache[$key] = array_values(array_unique($aliases));
|
||||||
|
}
|
||||||
|
|
||||||
protected function getDocBlockContext(\Reflector $reflector): Context
|
protected function getDocBlockContext(\Reflector $reflector): Context
|
||||||
{
|
{
|
||||||
if ($reflector instanceof \ReflectionMethod) {
|
if ($reflector instanceof \ReflectionMethod) {
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpstanImportType\Models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-type ArrayShape array{name: string, age: int}
|
||||||
|
*/
|
||||||
|
class Shapes
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpstanImportType\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-import-type ArrayShape from Shapes
|
||||||
|
*/
|
||||||
|
class Simple extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return ArrayShape
|
||||||
|
*/
|
||||||
|
public function getSomeArrayAttribute(): array
|
||||||
|
{
|
||||||
|
return ['name' => 'Taylor', 'age' => 40];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-return LocalShape
|
||||||
|
*/
|
||||||
|
public function getLocalAttribute(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpstanImportType;
|
||||||
|
|
||||||
|
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
|
||||||
|
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
|
||||||
|
|
||||||
|
class Test extends AbstractModelsCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Types imported with `@phpstan-import-type` are local aliases, not classes
|
||||||
|
* in the model's namespace, so they must not be prefixed with it.
|
||||||
|
*
|
||||||
|
* @link https://github.com/barryvdh/laravel-ide-helper/issues/1773
|
||||||
|
*/
|
||||||
|
public function testImportedTypeIsNotQualifiedWithTheModelNamespace(): void
|
||||||
|
{
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, ['--write' => true]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpstanImportType\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-import-type ArrayShape from Shapes
|
||||||
|
* @property int $id
|
||||||
|
* @property-read array $local
|
||||||
|
* @property-read ArrayShape $some_array
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple whereId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Simple extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return ArrayShape
|
||||||
|
*/
|
||||||
|
public function getSomeArrayAttribute(): array
|
||||||
|
{
|
||||||
|
return ['name' => 'Taylor', 'age' => 40];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-return LocalShape
|
||||||
|
*/
|
||||||
|
public function getLocalAttribute(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user