Skip to content

Commit 60ebf65

Browse files
authored
Merge branch 'master' into patch-1
2 parents defed2a + 578f552 commit 60ebf65

27 files changed

+109
-18
lines changed

src/FqsenResolver.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
use function implode;
2020
use function strpos;
2121

22+
/**
23+
* Resolver for Fqsen using Context information
24+
*
25+
* @psalm-immutable
26+
*/
2227
class FqsenResolver
2328
{
2429
/** @var string Definition of the NAMESPACE operator in PHP */

src/Type.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
namespace phpDocumentor\Reflection;
1515

16+
/**
17+
* @psalm-immutable
18+
*/
1619
interface Type
1720
{
1821
/**

src/TypeResolver.php

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ final class TypeResolver
9494
'iterable' => Iterable_::class,
9595
];
9696

97-
/** @var FqsenResolver */
97+
/**
98+
* @var FqsenResolver
99+
* @psalm-readonly
100+
*/
98101
private $fqsenResolver;
99102

100103
/**
@@ -120,6 +123,8 @@ public function __construct(?FqsenResolver $fqsenResolver = null)
120123
* @uses Context::getNamespace() to determine with what to prefix the type name.
121124
*
122125
* @param string $type The relative or absolute type.
126+
*
127+
* @psalm-pure
123128
*/
124129
public function resolve(string $type, ?Context $context = null) : Type
125130
{
@@ -144,6 +149,7 @@ public function resolve(string $type, ?Context $context = null) : Type
144149
throw new InvalidArgumentException('Unable to split the type string "' . $type . '" into tokens');
145150
}
146151

152+
/** @var ArrayIterator<int, string|null> $tokenIterator */
147153
$tokenIterator = new ArrayIterator($tokens);
148154

149155
return $this->parseTypes($tokenIterator, $context, self::PARSER_IN_COMPOUND);
@@ -152,9 +158,11 @@ public function resolve(string $type, ?Context $context = null) : Type
152158
/**
153159
* Analyse each tokens and creates types
154160
*
155-
* @param ArrayIterator<int, string> $tokens the iterator on tokens
161+
* @param ArrayIterator<int, string|null> $tokens the iterator on tokens
156162
* @param int $parserContext on of self::PARSER_* constants, indicating
157163
* the context where we are in the parsing
164+
*
165+
* @psalm-pure
158166
*/
159167
private function parseTypes(ArrayIterator $tokens, Context $context, int $parserContext) : Type
160168
{
@@ -163,7 +171,11 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
163171
$compoundToken = '|';
164172
while ($tokens->valid()) {
165173
$token = $tokens->current();
166-
if ($token === '|' || $token === '&') {
174+
if ($token === null) {
175+
throw new RuntimeException(
176+
'Unexpected nullable character'
177+
);
178+
} elseif ($token === '|' || $token === '&') {
167179
if (count($types) === 0) {
168180
throw new RuntimeException(
169181
'A type is missing before a type separator'
@@ -293,6 +305,8 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
293305
* @param string $type the type string, representing a single type
294306
*
295307
* @return Type|Array_|Object_
308+
*
309+
* @psalm-pure
296310
*/
297311
private function resolveSingleType(string $type, Context $context) : object
298312
{
@@ -342,6 +356,8 @@ public function addKeyword(string $keyword, string $typeClassName) : void
342356
* Detects whether the given type represents a PHPDoc keyword.
343357
*
344358
* @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
359+
*
360+
* @psalm-pure
345361
*/
346362
private function isKeyword(string $type) : bool
347363
{
@@ -352,6 +368,8 @@ private function isKeyword(string $type) : bool
352368
* Detects whether the given type represents a relative structural element name.
353369
*
354370
* @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
371+
*
372+
* @psalm-pure
355373
*/
356374
private function isPartialStructuralElementName(string $type) : bool
357375
{
@@ -360,6 +378,8 @@ private function isPartialStructuralElementName(string $type) : bool
360378

361379
/**
362380
* Tests whether the given type is a Fully Qualified Structural Element Name.
381+
*
382+
* @psalm-pure
363383
*/
364384
private function isFqsen(string $type) : bool
365385
{
@@ -368,6 +388,8 @@ private function isFqsen(string $type) : bool
368388

369389
/**
370390
* Resolves the given keyword (such as `string`) into a Type object representing that keyword.
391+
*
392+
* @psalm-pure
371393
*/
372394
private function resolveKeyword(string $type) : Type
373395
{
@@ -378,6 +400,8 @@ private function resolveKeyword(string $type) : Type
378400

379401
/**
380402
* Resolves the given FQSEN string into an FQSEN object.
403+
*
404+
* @psalm-pure
381405
*/
382406
private function resolveTypedObject(string $type, ?Context $context = null) : Object_
383407
{
@@ -387,7 +411,9 @@ private function resolveTypedObject(string $type, ?Context $context = null) : Ob
387411
/**
388412
* Resolves class string
389413
*
390-
* @param ArrayIterator<int, string> $tokens
414+
* @param ArrayIterator<int, null|string> $tokens
415+
*
416+
* @psalm-pure
391417
*/
392418
private function resolveClassString(ArrayIterator $tokens, Context $context) : Type
393419
{
@@ -401,15 +427,16 @@ private function resolveClassString(ArrayIterator $tokens, Context $context) : T
401427
);
402428
}
403429

404-
if ($tokens->current() !== '>') {
405-
if (empty($tokens->current())) {
430+
$token = $tokens->current();
431+
if ($token !== '>') {
432+
if (empty($token)) {
406433
throw new RuntimeException(
407434
'class-string: ">" is missing'
408435
);
409436
}
410437

411438
throw new RuntimeException(
412-
'Unexpected character "' . $tokens->current() . '", ">" is missing'
439+
'Unexpected character "' . $token . '", ">" is missing'
413440
);
414441
}
415442

@@ -419,9 +446,11 @@ private function resolveClassString(ArrayIterator $tokens, Context $context) : T
419446
/**
420447
* Resolves the collection values and keys
421448
*
422-
* @param ArrayIterator<int, string> $tokens
449+
* @param ArrayIterator<int, null|string> $tokens
423450
*
424451
* @return Array_|Iterable_|Collection
452+
*
453+
* @psalm-mutation-free
425454
*/
426455
private function resolveCollection(ArrayIterator $tokens, Type $classType, Context $context) : Type
427456
{
@@ -441,7 +470,8 @@ private function resolveCollection(ArrayIterator $tokens, Type $classType, Conte
441470
$valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
442471
$keyType = null;
443472

444-
if ($tokens->current() !== null && trim($tokens->current()) === ',') {
473+
$token = $tokens->current();
474+
if ($token !== null && trim($token) === ',') {
445475
// if we have a comma, then we just parsed the key type, not the value type
446476
$keyType = $valueType;
447477
if ($isArray) {
@@ -474,15 +504,16 @@ private function resolveCollection(ArrayIterator $tokens, Type $classType, Conte
474504
$valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
475505
}
476506

477-
if ($tokens->current() !== '>') {
478-
if (empty($tokens->current())) {
507+
$token = $tokens->current();
508+
if ($token !== '>') {
509+
if (empty($token)) {
479510
throw new RuntimeException(
480511
'Collection: ">" is missing'
481512
);
482513
}
483514

484515
throw new RuntimeException(
485-
'Unexpected character "' . $tokens->current() . '", ">" is missing'
516+
'Unexpected character "' . $token . '", ">" is missing'
486517
);
487518
}
488519

@@ -501,6 +532,9 @@ private function resolveCollection(ArrayIterator $tokens, Type $classType, Conte
501532
throw new RuntimeException('Invalid $classType provided');
502533
}
503534

535+
/**
536+
* @psalm-pure
537+
*/
504538
private function makeCollectionFromObject(Object_ $object, Type $valueType, ?Type $keyType = null) : Collection
505539
{
506540
return new Collection($object->getFqsen(), $valueType, $keyType);

src/Types/AbstractList.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
/**
1919
* Represents a list of values. This is an abstract class for Array_ and Collection.
20+
*
21+
* @psalm-immutable
2022
*/
2123
abstract class AbstractList implements Type
2224
{

src/Types/Array_.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
* 1. Untyped (`array`), where the key and value type is unknown and hence classified as 'Mixed_'.
2222
* 2. Types (`string[]`), where the value type is provided by preceding an opening and closing square bracket with a
2323
* type name.
24+
*
25+
* @psalm-immutable
2426
*/
2527
final class Array_ extends AbstractList
2628
{

src/Types/Boolean.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
/**
1919
* Value Object representing a Boolean type.
20+
*
21+
* @psalm-immutable
2022
*/
2123
final class Boolean implements Type
2224
{

src/Types/Callable_.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
/**
1919
* Value Object representing a Callable type.
20+
*
21+
* @psalm-immutable
2022
*/
2123
final class Callable_ implements Type
2224
{

src/Types/ClassString.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
/**
2020
* Value Object representing the type 'string'.
21+
*
22+
* @psalm-immutable
2123
*/
2224
final class ClassString implements Type
2325
{

src/Types/Collection.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
*
2727
* - ACollectionObject can be 'array' or an object that can act as an array
2828
* - aValueType and aKeyType can be any type expression
29+
*
30+
* @psalm-immutable
2931
*/
3032
final class Collection extends AbstractList
3133
{

src/Types/Compound.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,15 @@
2626
* using an OR operator (`|`). This combination of types signifies that whatever is associated with this compound type
2727
* may contain a value with any of the given types.
2828
*
29+
* @psalm-immutable
2930
* @template-implements IteratorAggregate<int, Type>
3031
*/
3132
final class Compound implements Type, IteratorAggregate
3233
{
33-
/** @var array<int, Type> */
34+
/**
35+
* @psalm-allow-private-mutation
36+
* @var array<int, Type>
37+
*/
3438
private $types = [];
3539

3640
/** @var string */

0 commit comments

Comments
 (0)