Skip to content

Commit dd9861e

Browse files
authored
Merge pull request #332 from villfa/feat/returns-reference
Support reference in method tag
2 parents 6baa6f8 + 29ed9ae commit dd9861e

File tree

2 files changed

+75
-12
lines changed

2 files changed

+75
-12
lines changed

src/DocBlock/Tags/Method.php

+33-12
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ final class Method extends BaseTag implements Factory\StaticMethod
5757
/** @var Type */
5858
private $returnType;
5959

60+
/** @var bool */
61+
private $returnsReference;
62+
6063
/**
6164
* @param array<int, array<string, Type|string>> $arguments
6265
* @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
@@ -66,19 +69,21 @@ public function __construct(
6669
array $arguments = [],
6770
?Type $returnType = null,
6871
bool $static = false,
69-
?Description $description = null
72+
?Description $description = null,
73+
bool $returnsReference = false
7074
) {
7175
Assert::stringNotEmpty($methodName);
7276

7377
if ($returnType === null) {
7478
$returnType = new Void_();
7579
}
7680

77-
$this->methodName = $methodName;
78-
$this->arguments = $this->filterArguments($arguments);
79-
$this->returnType = $returnType;
80-
$this->isStatic = $static;
81-
$this->description = $description;
81+
$this->methodName = $methodName;
82+
$this->arguments = $this->filterArguments($arguments);
83+
$this->returnType = $returnType;
84+
$this->isStatic = $static;
85+
$this->description = $description;
86+
$this->returnsReference = $returnsReference;
8287
}
8388

8489
public static function create(
@@ -95,11 +100,13 @@ public static function create(
95100
// 2. optionally the keyword "static" followed by whitespace
96101
// 3. optionally a word with underscores followed by whitespace : as
97102
// type for the return value
98-
// 4. then optionally a word with underscores followed by () and
103+
// 4. optionally an ampersand followed or not by whitespace : as
104+
// a reference
105+
// 5. then optionally a word with underscores followed by () and
99106
// whitespace : as method name as used by phpDocumentor
100-
// 5. then a word with underscores, followed by ( and any character
107+
// 6. then a word with underscores, followed by ( and any character
101108
// until a ) and whitespace : as method name with signature
102-
// 6. any remaining text : as description
109+
// 7. any remaining text : as description
103110
if (
104111
!preg_match(
105112
'/^
@@ -122,6 +129,11 @@ public static function create(
122129
)
123130
\s+
124131
)?
132+
# Returns reference
133+
(?:
134+
(&)
135+
\s*
136+
)?
125137
# Method name
126138
([\w_]+)
127139
# Arguments
@@ -139,14 +151,16 @@ public static function create(
139151
return null;
140152
}
141153

142-
[, $static, $returnType, $methodName, $argumentLines, $description] = $matches;
154+
[, $static, $returnType, $returnsReference, $methodName, $argumentLines, $description] = $matches;
143155

144156
$static = $static === 'static';
145157

146158
if ($returnType === '') {
147159
$returnType = 'void';
148160
}
149161

162+
$returnsReference = $returnsReference === '&';
163+
150164
$returnType = $typeResolver->resolve($returnType, $context);
151165
$description = $descriptionFactory->create($description, $context);
152166

@@ -172,7 +186,7 @@ public static function create(
172186
}
173187
}
174188

175-
return new static($methodName, $arguments, $returnType, $static, $description);
189+
return new static($methodName, $arguments, $returnType, $static, $description, $returnsReference);
176190
}
177191

178192
/**
@@ -207,6 +221,11 @@ public function getReturnType(): Type
207221
return $this->returnType;
208222
}
209223

224+
public function returnsReference(): bool
225+
{
226+
return $this->returnsReference;
227+
}
228+
210229
public function __toString(): string
211230
{
212231
$arguments = [];
@@ -228,9 +247,11 @@ public function __toString(): string
228247

229248
$methodName = $this->methodName;
230249

250+
$reference = $this->returnsReference ? '&' : '';
251+
231252
return $static
232253
. ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '')
233-
. ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $methodName : '')
254+
. ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $reference . $methodName : '')
234255
. $argumentStr
235256
. ($description !== '' ? ' ' . $description : '');
236257
}

tests/unit/DocBlock/Tags/MethodTest.php

+42
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ public function testFactoryMethod(): void
339339
$this->assertEquals($expectedArguments, $fixture->getArguments());
340340
$this->assertInstanceOf(Void_::class, $fixture->getReturnType());
341341
$this->assertSame($description, $fixture->getDescription());
342+
$this->assertFalse($fixture->returnsReference());
342343
}
343344

344345
/**
@@ -370,6 +371,7 @@ public function testReturnTypeThis(): void
370371
$this->assertSame('static $this myMethod()', (string) $fixture);
371372
$this->assertSame('myMethod', $fixture->getMethodName());
372373
$this->assertInstanceOf(This::class, $fixture->getReturnType());
374+
$this->assertFalse($fixture->returnsReference());
373375
}
374376

375377
/**
@@ -401,6 +403,7 @@ public function testReturnTypeNoneWithLongMethodName(): void
401403
$this->assertSame('void myVeryLongMethodName(mixed $node)', (string) $fixture);
402404
$this->assertSame('myVeryLongMethodName', $fixture->getMethodName());
403405
$this->assertInstanceOf(Void_::class, $fixture->getReturnType());
406+
$this->assertFalse($fixture->returnsReference());
404407
}
405408

406409
/**
@@ -542,6 +545,7 @@ public function testCreateMethodParenthesisMissing(): void
542545
$this->assertEquals([], $fixture->getArguments());
543546
$this->assertInstanceOf(Void_::class, $fixture->getReturnType());
544547
$this->assertSame($description, $fixture->getDescription());
548+
$this->assertFalse($fixture->returnsReference());
545549
}
546550

547551
/**
@@ -578,6 +582,7 @@ public function testCreateMethodEmptyArguments(): void
578582
$this->assertEquals([], $fixture->getArguments());
579583
$this->assertInstanceOf(Void_::class, $fixture->getReturnType());
580584
$this->assertSame($description, $fixture->getDescription());
585+
$this->assertFalse($fixture->returnsReference());
581586
}
582587

583588
/**
@@ -613,6 +618,7 @@ public function testCreateWithoutReturnType(): void
613618
$this->assertEquals([], $fixture->getArguments());
614619
$this->assertInstanceOf(Void_::class, $fixture->getReturnType());
615620
$this->assertSame($description, $fixture->getDescription());
621+
$this->assertFalse($fixture->returnsReference());
616622
}
617623

618624
/**
@@ -656,4 +662,40 @@ public function testCreateWithMixedReturnTypes(): void
656662
$fixture->getReturnType()
657663
);
658664
}
665+
666+
/**
667+
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Method::<public>
668+
* @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory
669+
* @uses \phpDocumentor\Reflection\TypeResolver
670+
* @uses \phpDocumentor\Reflection\DocBlock\Description
671+
* @uses \phpDocumentor\Reflection\Fqsen
672+
* @uses \phpDocumentor\Reflection\Types\Context
673+
* @uses \phpDocumentor\Reflection\Types\String_
674+
*
675+
* @covers ::create
676+
*/
677+
public function testCreateWithReference(): void
678+
{
679+
$descriptionFactory = m::mock(DescriptionFactory::class);
680+
$resolver = new TypeResolver();
681+
$context = new Context('');
682+
683+
$description = new Description('');
684+
685+
$descriptionFactory->shouldReceive('create')->with('', $context)->andReturn($description);
686+
687+
$fixture = Method::create(
688+
'string &myMethod()',
689+
$resolver,
690+
$descriptionFactory,
691+
$context
692+
);
693+
694+
$this->assertSame('string &myMethod()', (string) $fixture);
695+
$this->assertSame('myMethod', $fixture->getMethodName());
696+
$this->assertEquals([], $fixture->getArguments());
697+
$this->assertInstanceOf(String_::class, $fixture->getReturnType());
698+
$this->assertSame($description, $fixture->getDescription());
699+
$this->assertTrue($fixture->returnsReference());
700+
}
659701
}

0 commit comments

Comments
 (0)