Skip to content

Commit f4e0fc3

Browse files
authored
Allow for PhpDoc for macros with union types (#1148)
* Allow for PhpDoc for macros with union types * Replace null coalescing operator * Test init PhpDoc for macros with parameter union types * Allow for PhpDoc for macros with union return types * Add helper method to Macro class * Add changelog entry * Format * Complement changelog with PR link * Add missing return * Fix test for PHP < 8 * Rewrite PHP 8 test using eval() * Remove obsolete test class * Suppress Psalm errors for undefined ReflectionUnionType class * Remove unreachable return statement
1 parent af84c78 commit f4e0fc3

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ All notable changes to this project will be documented in this file.
4040
- Generate PHPDoc for Laravel 8.x factories [\#1074 / ahmed-aliraqi](https://github.com/barryvdh/laravel-ide-helper/pull/1074)
4141
- Add a comment to a property like table columns [\#1168 / biiiiiigmonster](https://github.com/barryvdh/laravel-ide-helper/pull/1168)
4242
- Added `post_migrate` hook to run commands after a migration [\#1163 / netpok](https://github.com/barryvdh/laravel-ide-helper/pull/1163)
43+
- Allow for PhpDoc for macros with union types [\#1148 / riesjart](https://github.com/barryvdh/laravel-ide-helper/pull/1148)
4344

4445
### Fixed
4546
- Error when generating helper for invokable classes [\#1124 / standaniels](https://github.com/barryvdh/laravel-ide-helper/pull/1124)

src/Macro.php

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,16 @@ protected function initPhpDoc($method)
4242
// Add macro parameters if they are missed in original docblock
4343
if (!$this->phpdoc->hasTag('param')) {
4444
foreach ($method->getParameters() as $parameter) {
45-
$type = $parameter->hasType() ? $parameter->getType()->getName() : 'mixed';
46-
$type .= $parameter->hasType() && $parameter->getType()->allowsNull() ? '|null' : '';
45+
$reflectionType = $parameter->getType();
46+
47+
$type = $this->concatReflectionTypes($reflectionType);
48+
49+
/** @psalm-suppress UndefinedClass */
50+
if ($reflectionType && !$reflectionType instanceof \ReflectionUnionType && $reflectionType->allowsNull()) {
51+
$type .= '|null';
52+
}
53+
54+
$type = $type ?: 'mixed';
4755

4856
$name = $parameter->isVariadic() ? '...' : '';
4957
$name .= '$' . $parameter->getName();
@@ -57,14 +65,31 @@ protected function initPhpDoc($method)
5765
$builder = EloquentBuilder::class;
5866
$return = $method->getReturnType();
5967

60-
$type = $return->getName();
61-
$type .= $this->root === "\\{$builder}" && $return->getName() === $builder ? '|static' : '';
62-
$type .= $return->allowsNull() ? '|null' : '';
68+
$type = $this->concatReflectionTypes($return);
69+
70+
/** @psalm-suppress UndefinedClass */
71+
if (!$return instanceof \ReflectionUnionType) {
72+
$type .= $this->root === "\\{$builder}" && $return->getName() === $builder ? '|static' : '';
73+
$type .= $return->allowsNull() ? '|null' : '';
74+
}
6375

6476
$this->phpdoc->appendTag(Tag::createInstance("@return {$type}"));
6577
}
6678
}
6779

80+
protected function concatReflectionTypes(?\ReflectionType $type): string
81+
{
82+
/** @psalm-suppress UndefinedClass */
83+
$returnTypes = $type instanceof \ReflectionUnionType
84+
? $type->getTypes()
85+
: [$type];
86+
87+
return Collection::make($returnTypes)
88+
->filter()
89+
->map->getName()
90+
->implode('|');
91+
}
92+
6893
protected function addLocationToPhpDoc()
6994
{
7095
if ($this->method->name === '__invoke') {

tests/MacroTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,29 @@ function ($a = null): int {
188188
$this->assertEquals('@return \stdClass|null rrrrrrr', $this->tagsToString($phpdoc, 'return'));
189189
}
190190

191+
public function testInitPhpDocParamsWithUnionTypes(): void
192+
{
193+
if (PHP_VERSION_ID < 80000) {
194+
$this->markTestSkipped('This test requires PHP 8.0 or higher');
195+
}
196+
197+
$phpdoc = (new MacroMock())->getPhpDoc(eval(<<<'PHP'
198+
return new ReflectionFunction(
199+
/**
200+
* Test docblock.
201+
*/
202+
function (\Stringable|string $a = null): \Stringable|string|null {
203+
return $a;
204+
}
205+
);
206+
PHP));
207+
208+
$this->assertNotNull($phpdoc);
209+
$this->assertStringContainsString('Test docblock', $phpdoc->getText());
210+
$this->assertEquals('@param \Stringable|string|null $a', $this->tagsToString($phpdoc, 'param'));
211+
$this->assertEquals('@return \Stringable|string|null', $this->tagsToString($phpdoc, 'return'));
212+
}
213+
191214
protected function tagsToString(DocBlock $docBlock, string $name)
192215
{
193216
$tags = $docBlock->getTagsByName($name);

0 commit comments

Comments
 (0)