@@ -93,7 +93,10 @@ final class TypeResolver
93
93
'iterable ' => Iterable_::class,
94
94
];
95
95
96
- /** @var FqsenResolver */
96
+ /**
97
+ * @var FqsenResolver
98
+ * @psalm-readonly
99
+ */
97
100
private $ fqsenResolver ;
98
101
99
102
/**
@@ -119,6 +122,8 @@ public function __construct(?FqsenResolver $fqsenResolver = null)
119
122
* @uses Context::getNamespace() to determine with what to prefix the type name.
120
123
*
121
124
* @param string $type The relative or absolute type.
125
+ *
126
+ * @psalm-pure
122
127
*/
123
128
public function resolve (string $ type , ?Context $ context = null ) : Type
124
129
{
@@ -143,6 +148,7 @@ public function resolve(string $type, ?Context $context = null) : Type
143
148
throw new InvalidArgumentException ('Unable to split the type string " ' . $ type . '" into tokens ' );
144
149
}
145
150
151
+ /** @var ArrayIterator<int, string|null> $tokenIterator */
146
152
$ tokenIterator = new ArrayIterator ($ tokens );
147
153
148
154
return $ this ->parseTypes ($ tokenIterator , $ context , self ::PARSER_IN_COMPOUND );
@@ -151,18 +157,23 @@ public function resolve(string $type, ?Context $context = null) : Type
151
157
/**
152
158
* Analyse each tokens and creates types
153
159
*
154
- * @param ArrayIterator<int, string> $tokens the iterator on tokens
160
+ * @param ArrayIterator<int, string|null > $tokens the iterator on tokens
155
161
* @param int $parserContext on of self::PARSER_* constants, indicating
156
162
* the context where we are in the parsing
163
+ *
164
+ * @psalm-pure
157
165
*/
158
166
private function parseTypes (ArrayIterator $ tokens , Context $ context , int $ parserContext ) : Type
159
167
{
160
168
$ types = [];
161
169
$ token = '' ;
162
170
while ($ tokens ->valid ()) {
163
171
$ token = $ tokens ->current ();
164
-
165
- if ($ token === '| ' ) {
172
+ if ($ token === null ) {
173
+ throw new RuntimeException (
174
+ 'Unexpected nullable character '
175
+ );
176
+ } elseif ($ token === '| ' ) {
166
177
if (count ($ types ) === 0 ) {
167
178
throw new RuntimeException (
168
179
'A type is missing before a type separator '
@@ -287,6 +298,8 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
287
298
* @param string $type the type string, representing a single type
288
299
*
289
300
* @return Type|Array_|Object_
301
+ *
302
+ * @psalm-pure
290
303
*/
291
304
private function resolveSingleType (string $ type , Context $ context ) : object
292
305
{
@@ -338,6 +351,8 @@ public function addKeyword(string $keyword, string $typeClassName) : void
338
351
* Detects whether the given type represents an array.
339
352
*
340
353
* @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
354
+ *
355
+ * @psalm-pure
341
356
*/
342
357
private function isTypedArray (string $ type ) : bool
343
358
{
@@ -348,6 +363,8 @@ private function isTypedArray(string $type) : bool
348
363
* Detects whether the given type represents a PHPDoc keyword.
349
364
*
350
365
* @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
366
+ *
367
+ * @psalm-pure
351
368
*/
352
369
private function isKeyword (string $ type ) : bool
353
370
{
@@ -358,6 +375,8 @@ private function isKeyword(string $type) : bool
358
375
* Detects whether the given type represents a relative structural element name.
359
376
*
360
377
* @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
378
+ *
379
+ * @psalm-pure
361
380
*/
362
381
private function isPartialStructuralElementName (string $ type ) : bool
363
382
{
@@ -366,6 +385,8 @@ private function isPartialStructuralElementName(string $type) : bool
366
385
367
386
/**
368
387
* Tests whether the given type is a Fully Qualified Structural Element Name.
388
+ *
389
+ * @psalm-pure
369
390
*/
370
391
private function isFqsen (string $ type ) : bool
371
392
{
@@ -374,6 +395,8 @@ private function isFqsen(string $type) : bool
374
395
375
396
/**
376
397
* Resolves the given typed array string (i.e. `string[]`) into an Array object with the right types set.
398
+ *
399
+ * @psalm-pure
377
400
*/
378
401
private function resolveTypedArray (string $ type , Context $ context ) : Array_
379
402
{
@@ -382,6 +405,8 @@ private function resolveTypedArray(string $type, Context $context) : Array_
382
405
383
406
/**
384
407
* Resolves the given keyword (such as `string`) into a Type object representing that keyword.
408
+ *
409
+ * @psalm-pure
385
410
*/
386
411
private function resolveKeyword (string $ type ) : Type
387
412
{
@@ -392,6 +417,8 @@ private function resolveKeyword(string $type) : Type
392
417
393
418
/**
394
419
* Resolves the given FQSEN string into an FQSEN object.
420
+ *
421
+ * @psalm-pure
395
422
*/
396
423
private function resolveTypedObject (string $ type , ?Context $ context = null ) : Object_
397
424
{
@@ -401,7 +428,9 @@ private function resolveTypedObject(string $type, ?Context $context = null) : Ob
401
428
/**
402
429
* Resolves class string
403
430
*
404
- * @param ArrayIterator<int, string> $tokens
431
+ * @param ArrayIterator<int, null|string> $tokens
432
+ *
433
+ * @psalm-pure
405
434
*/
406
435
private function resolveClassString (ArrayIterator $ tokens , Context $ context ) : Type
407
436
{
@@ -415,15 +444,16 @@ private function resolveClassString(ArrayIterator $tokens, Context $context) : T
415
444
);
416
445
}
417
446
418
- if ($ tokens ->current () !== '> ' ) {
419
- if (empty ($ tokens ->current ())) {
447
+ $ token = $ tokens ->current ();
448
+ if ($ token !== '> ' ) {
449
+ if (empty ($ token )) {
420
450
throw new RuntimeException (
421
451
'class-string: ">" is missing '
422
452
);
423
453
}
424
454
425
455
throw new RuntimeException (
426
- 'Unexpected character " ' . $ tokens -> current () . '", ">" is missing '
456
+ 'Unexpected character " ' . $ token . '", ">" is missing '
427
457
);
428
458
}
429
459
@@ -433,9 +463,11 @@ private function resolveClassString(ArrayIterator $tokens, Context $context) : T
433
463
/**
434
464
* Resolves the collection values and keys
435
465
*
436
- * @param ArrayIterator<int, string> $tokens
466
+ * @param ArrayIterator<int, null| string> $tokens
437
467
*
438
468
* @return Array_|Iterable_|Collection
469
+ *
470
+ * @psalm-mutation-free
439
471
*/
440
472
private function resolveCollection (ArrayIterator $ tokens , Type $ classType , Context $ context ) : Type
441
473
{
@@ -455,7 +487,8 @@ private function resolveCollection(ArrayIterator $tokens, Type $classType, Conte
455
487
$ valueType = $ this ->parseTypes ($ tokens , $ context , self ::PARSER_IN_COLLECTION_EXPRESSION );
456
488
$ keyType = null ;
457
489
458
- if ($ tokens ->current () !== null && trim ($ tokens ->current ()) === ', ' ) {
490
+ $ token = $ tokens ->current ();
491
+ if ($ token !== null && trim ($ token ) === ', ' ) {
459
492
// if we have a comma, then we just parsed the key type, not the value type
460
493
$ keyType = $ valueType ;
461
494
if ($ isArray ) {
@@ -488,15 +521,16 @@ private function resolveCollection(ArrayIterator $tokens, Type $classType, Conte
488
521
$ valueType = $ this ->parseTypes ($ tokens , $ context , self ::PARSER_IN_COLLECTION_EXPRESSION );
489
522
}
490
523
491
- if ($ tokens ->current () !== '> ' ) {
492
- if (empty ($ tokens ->current ())) {
524
+ $ token = $ tokens ->current ();
525
+ if ($ token !== '> ' ) {
526
+ if (empty ($ token )) {
493
527
throw new RuntimeException (
494
528
'Collection: ">" is missing '
495
529
);
496
530
}
497
531
498
532
throw new RuntimeException (
499
- 'Unexpected character " ' . $ tokens -> current () . '", ">" is missing '
533
+ 'Unexpected character " ' . $ token . '", ">" is missing '
500
534
);
501
535
}
502
536
@@ -515,6 +549,9 @@ private function resolveCollection(ArrayIterator $tokens, Type $classType, Conte
515
549
throw new RuntimeException ('Invalid $classType provided ' );
516
550
}
517
551
552
+ /**
553
+ * @psalm-pure
554
+ */
518
555
private function makeCollectionFromObject (Object_ $ object , Type $ valueType , ?Type $ keyType = null ) : Collection
519
556
{
520
557
return new Collection ($ object ->getFqsen (), $ valueType , $ keyType );
0 commit comments