From b72689755b58ad9e2044f78e19278f54b97c1321 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Wed, 1 Apr 2020 22:44:26 +0200 Subject: [PATCH] Infer return type from reflection if no phpdoc given --- src/Console/ModelsCommand.php | 47 +++++++++++-- .../ModelsCommand/Getter/Models/Simple.php | 51 +++++++++++++- tests/Console/ModelsCommand/Getter/Test.php | 68 +++++++++++++++++-- 3 files changed, 153 insertions(+), 13 deletions(-) diff --git a/src/Console/ModelsCommand.php b/src/Console/ModelsCommand.php index ed9d2d6..7f57627 100644 --- a/src/Console/ModelsCommand.php +++ b/src/Console/ModelsCommand.php @@ -10,19 +10,19 @@ namespace Barryvdh\LaravelIdeHelper\Console; +use Barryvdh\Reflection\DocBlock; +use Barryvdh\Reflection\DocBlock\Context; +use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; +use Barryvdh\Reflection\DocBlock\Tag; use Composer\Autoload\ClassMapGenerator; use Illuminate\Console\Command; use Illuminate\Database\Eloquent\Relations\Relation; -use Illuminate\Support\Str; use Illuminate\Filesystem\Filesystem; +use Illuminate\Support\Str; use ReflectionClass; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Barryvdh\Reflection\DocBlock; -use Barryvdh\Reflection\DocBlock\Context; -use Barryvdh\Reflection\DocBlock\Tag; -use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; /** * A command to generate autocomplete information for your IDE @@ -438,7 +438,7 @@ class ModelsCommand extends Command $name = Str::snake(substr($method, 3, -9)); if (!empty($name)) { $reflection = new \ReflectionMethod($model, $method); - $type = $this->getReturnTypeFromDocBlock($reflection); + $type = $this->getReturnType($reflection); $this->setProperty($name, $type, true, null); } } elseif (Str::startsWith($method, 'set') && Str::endsWith( @@ -814,6 +814,16 @@ class ModelsCommand extends Command return $this->laravel['config']->get('ide-helper.model_camel_case_properties', false); } + protected function getReturnType(\ReflectionMethod $reflection): ?string + { + $type = $this->getReturnTypeFromDocBlock($reflection); + if ($type) { + return $type; + } + + return $this->getReturnTypeFromReflection($reflection); + } + /** * Get method return type based on it DocBlock comment * @@ -833,6 +843,29 @@ class ModelsCommand extends Command return $type; } + protected function getReturnTypeFromReflection(\ReflectionMethod $reflection): ?string + { + $returnType = $reflection->getReturnType(); + if (!$returnType) { + return null; + } + + $type = $returnType instanceof \ReflectionNamedType + ? $returnType->getName() + : (string)$returnType; + + if (!$returnType->isBuiltin()) { + $type = '\\' . $type; + } + + if ($returnType->allowsNull()) { + $type .= '|null'; + } + + return $type; + } + + /** * Generates methods provided by the SoftDeletes trait * @param \Illuminate\Database\Eloquent\Model $model diff --git a/tests/Console/ModelsCommand/Getter/Models/Simple.php b/tests/Console/ModelsCommand/Getter/Models/Simple.php index 926f84f..23d6e91 100644 --- a/tests/Console/ModelsCommand/Getter/Models/Simple.php +++ b/tests/Console/ModelsCommand/Getter/Models/Simple.php @@ -47,11 +47,58 @@ class Simple extends Model { } - public function getAttributeReturnsImportedClass(): DateTime + public function getAttributeReturnsImportedClassAttribute(): DateTime { } - public function getAttributeReturnsFqnClass(): \Illuminate\Support\Facades\Date + public function getAttributeReturnsFqnClassAttribute(): \Illuminate\Support\Facades\Date + { + } + + public function getAttributeReturnsArrayAttribute(): array + { + } + + public function getAttributeReturnsNullableArrayAttribute(): ?array + { + } + + public function getAttributeReturnsStdClassAttribute(): \stdClass + { + } + + public function getAttributeReturnsNullableStdClassAttribute(): ?\stdClass + { + } + + public function getAttributeReturnsBoolAttribute(): bool + { + } + + public function getAttributeReturnsNullableBoolAttribute(): ?bool + { + } + + public function getAttributeReturnsFloatAttribute(): bool + { + } + + public function getAttributeReturnsNullableFloatAttribute(): ?bool + { + } + + public function getAttributeReturnsCallableAttribute(): callable + { + } + + public function getAttributeReturnsNullableCallableAttribute(): ?callable + { + } + + /** + * Doesn't make sense, but… + */ + public function getAttributeReturnsVoidAttribute(): void { } } diff --git a/tests/Console/ModelsCommand/Getter/Test.php b/tests/Console/ModelsCommand/Getter/Test.php index 894efa5..3bf60ba 100644 --- a/tests/Console/ModelsCommand/Getter/Test.php +++ b/tests/Console/ModelsCommand/Getter/Test.php @@ -62,12 +62,25 @@ use Illuminate\Database\Eloquent\Model; * Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Getter\Models\Simple * * @property integer $id - * @property-read mixed $attribute_return_type_int_or_null + * @property-read int|null $attribute_return_type_int_or_null + * @property-read array $attribute_returns_array + * @property-read bool $attribute_returns_bool + * @property-read callable $attribute_returns_callable + * @property-read bool $attribute_returns_float + * @property-read \Illuminate\Support\Facades\Date $attribute_returns_fqn_class + * @property-read \DateTime $attribute_returns_imported_class + * @property-read array|null $attribute_returns_nullable_array + * @property-read bool|null $attribute_returns_nullable_bool + * @property-read callable|null $attribute_returns_nullable_callable + * @property-read bool|null $attribute_returns_nullable_float + * @property-read \stdClass|null $attribute_returns_nullable_std_class + * @property-read \stdClass $attribute_returns_std_class + * @property-read void $attribute_returns_void * @property-read \what|\ever|\we-write/here $attribute_takes_phpdoc_literal * @property-read int $attribute_with_int_return_phpdoc * @property-read string $attribute_with_int_return_type_and_but_phpdoc_string * @property-read int $attribute_with_int_return_type_and_phpdoc - * @property-read mixed $attribute_with_int_return_type + * @property-read int $attribute_with_int_return_type * @property-read mixed $attribute_without_type * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Getter\Models\Simple newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Getter\Models\Simple newQuery() @@ -117,11 +130,58 @@ class Simple extends Model { } - public function getAttributeReturnsImportedClass(): DateTime + public function getAttributeReturnsImportedClassAttribute(): DateTime { } - public function getAttributeReturnsFqnClass(): \Illuminate\Support\Facades\Date + public function getAttributeReturnsFqnClassAttribute(): \Illuminate\Support\Facades\Date + { + } + + public function getAttributeReturnsArrayAttribute(): array + { + } + + public function getAttributeReturnsNullableArrayAttribute(): ?array + { + } + + public function getAttributeReturnsStdClassAttribute(): \stdClass + { + } + + public function getAttributeReturnsNullableStdClassAttribute(): ?\stdClass + { + } + + public function getAttributeReturnsBoolAttribute(): bool + { + } + + public function getAttributeReturnsNullableBoolAttribute(): ?bool + { + } + + public function getAttributeReturnsFloatAttribute(): bool + { + } + + public function getAttributeReturnsNullableFloatAttribute(): ?bool + { + } + + public function getAttributeReturnsCallableAttribute(): callable + { + } + + public function getAttributeReturnsNullableCallableAttribute(): ?callable + { + } + + /** + * Doesn't make sense, but… + */ + public function getAttributeReturnsVoidAttribute(): void { } }