Skip to content

Commit 19dd184

Browse files
committed
Support braces in types for @return
In this change, I have introduced a miniature automaton-light to parse the type from the @return body. This will prevent issues with people using generics and other unsupported forms of types. This change does _not_ allow for the use of Generics or similar; the TypeResolver will still fail to resolve this type. This will remove a breaking issue in consuming applications where a runtime exception used to be thrown. Please note that this change is only for @return; other tags still need to be done. This will resolve issue #186
1 parent c19ab7e commit 19dd184

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

src/DocBlock/Tags/Return_.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,10 @@ public static function create(
5050
Assert::notNull($typeResolver);
5151
Assert::notNull($descriptionFactory);
5252

53-
$parts = preg_split('/\s+/Su', $body, 2);
54-
Assert::isArray($parts);
53+
list($type, $description) = self::splitBodyIntoTypeAndTheRest($body);
5554

56-
$type = $typeResolver->resolve($parts[0] ?? '', $context);
57-
$description = $descriptionFactory->create($parts[1] ?? '', $context);
55+
$type = $typeResolver->resolve($type, $context);
56+
$description = $descriptionFactory->create($description, $context);
5857

5958
return new static($type, $description);
6059
}
@@ -71,4 +70,29 @@ public function __toString() : string
7170
{
7271
return $this->type . ' ' . (string) $this->description;
7372
}
73+
74+
private static function splitBodyIntoTypeAndTheRest(string $body) : array
75+
{
76+
$type = '';
77+
$nestingLevel = 0;
78+
for ($i = 0; $i < strlen($body); $i++) {
79+
$character = $body[$i];
80+
81+
if (trim($character) === '' && $nestingLevel === 0) {
82+
break;
83+
}
84+
85+
$type .= $character;
86+
if (in_array($character, ['<', '(', '[', '{'])) {
87+
$nestingLevel++;
88+
}
89+
if (in_array($character, ['>', ')', ']', '}'])) {
90+
$nestingLevel--;
91+
}
92+
}
93+
94+
$description = trim(substr($body, strlen($type)));
95+
96+
return [$type, $description];
97+
}
7498
}

tests/unit/DocBlock/Tags/ReturnTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,41 @@ public function testFactoryMethod() : void
148148
$this->assertSame($description, $fixture->getDescription());
149149
}
150150

151+
/**
152+
* This test checks whether a braces in a Type are allowed.
153+
*
154+
* The advent of generics poses a few issues, one of them is that spaces can now be part of a type. In the past we
155+
* could purely rely on spaces to split the individual parts of the body of a tag; but when there is a type in play
156+
* we now need to check for braces.
157+
*
158+
* This test tests whether an error occurs demonstrating that the braces were taken into account; this test is still
159+
* expected to produce an exception because the TypeResolver does not support generics.
160+
*
161+
* @covers ::create
162+
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Return_::<public>
163+
* @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory
164+
* @uses \phpDocumentor\Reflection\TypeResolver
165+
* @uses \phpDocumentor\Reflection\DocBlock\Description
166+
* @uses \phpDocumentor\Reflection\Types\String_
167+
* @uses \phpDocumentor\Reflection\Types\Context
168+
*/
169+
public function testFactoryMethodWithGenericWithSpace()
170+
{
171+
$this->expectException(\InvalidArgumentException::class);
172+
$this->expectExceptionMessage('"\array😁<string,😁 😁string>" is not a valid Fqsen.');
173+
174+
$descriptionFactory = m::mock(DescriptionFactory::class);
175+
$resolver = new TypeResolver();
176+
$context = new Context('');
177+
178+
$description = new Description('My Description');
179+
$descriptionFactory->shouldReceive('create')
180+
->with('My Description', $context)
181+
->andReturn($description);
182+
183+
Return_::create('array😁<string,😁 string> My Description', $resolver, $descriptionFactory, $context);
184+
}
185+
151186
/**
152187
* @covers ::create
153188
*/

0 commit comments

Comments
 (0)