Skip to content

Commit 9c0562f

Browse files
committed
Unclosed array expression should throw exception
In the current implementation we do not take into account that people may try the following notation: `@var array(string => string|null)` At the moment this is interpreted as an Array Expression but fails because the space causes the parser to see this as `array(string`, meaning an unclosed array expression. This change introduces a new RuntimeException that is thrown in this situation, it is up to the consumer of this library to deal with this situation however it deems best.
1 parent 8049085 commit 9c0562f

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

src/TypeResolver.php

+13-14
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,16 @@ final class TypeResolver
3030
/** @var string Definition of the NAMESPACE operator in PHP */
3131
const OPERATOR_NAMESPACE = '\\';
3232

33-
/** @var integer the iterator parser is inside a compound context */
33+
/** @var int the iterator parser is inside a compound context */
3434
const PARSER_IN_COMPOUND = 0;
3535

36-
/** @var integer the iterator parser is inside a nullable expression context */
36+
/** @var int the iterator parser is inside a nullable expression context */
3737
const PARSER_IN_NULLABLE = 1;
3838

39-
/** @var integer the iterator parser is inside an array expression context */
39+
/** @var int the iterator parser is inside an array expression context */
4040
const PARSER_IN_ARRAY_EXPRESSION = 2;
4141

42-
/** @var integer the iterator parser is inside a collection expression context */
42+
/** @var int the iterator parser is inside a collection expression context */
4343
const PARSER_IN_COLLECTION_EXPRESSION = 3;
4444

4545
/** @var string[] List of recognized keywords and unto which Value Object they map */
@@ -176,18 +176,21 @@ private function parseTypes(\ArrayIterator $tokens, Context $context, $parserCon
176176

177177
$resolvedType = new Array_($type);
178178

179-
// we generates arrays corresponding to the number of '[]'
180-
// after the ')'
181-
$numberOfArrays = (strlen($tokens->current()) - 1) / 2;
179+
$token = $tokens->current();
180+
// Someone did not properly close their array expression ..
181+
if ($token === null) {
182+
break;
183+
}
184+
185+
// we generate arrays corresponding to the number of '[]' after the ')'
186+
$numberOfArrays = (strlen($token) - 1) / 2;
182187
for ($i = 0; $i < $numberOfArrays - 1; ++$i) {
183188
$resolvedType = new Array_($resolvedType);
184189
}
185190

186191
$types[] = $resolvedType;
187192
$tokens->next();
188-
} elseif ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION
189-
&& $token[0] === ')'
190-
) {
193+
} elseif ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION && $token[0] === ')') {
191194
break;
192195
} elseif ($token === '<') {
193196
if (count($types) === 0) {
@@ -241,10 +244,6 @@ private function parseTypes(\ArrayIterator $tokens, Context $context, $parserCon
241244
'A type is missing in a collection expression'
242245
);
243246
}
244-
245-
throw new \RuntimeException(
246-
'No types in a compound list'
247-
);
248247
} elseif (count($types) === 1) {
249248
return $types[0];
250249
}

tests/unit/TypeResolverTest.php

+23
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,29 @@ public function testResolvingArrayOfArrayExpressionTypes()
390390
$this->assertInstanceOf(Object_::class, $secondType);
391391
}
392392

393+
/**
394+
* @covers ::__construct
395+
* @covers ::resolve
396+
* @covers ::<private>
397+
*
398+
* @uses \phpDocumentor\Reflection\Types\Context
399+
* @uses \phpDocumentor\Reflection\Types\Compound
400+
* @uses \phpDocumentor\Reflection\Types\Array_
401+
* @uses \phpDocumentor\Reflection\Types\Object_
402+
* @uses \phpDocumentor\Reflection\Fqsen
403+
* @uses \phpDocumentor\Reflection\FqsenResolver
404+
*/
405+
public function testReturnEmptyCompoundOnAnUnclosedArrayExpressionType()
406+
{
407+
$fixture = new TypeResolver();
408+
409+
/** @var Compound $resolvedType */
410+
$resolvedType = $fixture->resolve('(string|\stdClass', new Context(''));
411+
412+
$this->assertInstanceOf(Compound::class, $resolvedType);
413+
$this->assertSame('', (string)$resolvedType);
414+
}
415+
393416
/**
394417
* @covers ::__construct
395418
* @covers ::resolve

0 commit comments

Comments
 (0)