Skip to content

Commit c0441d1

Browse files
committed
Enable totallyTyped=true and bump type coverage to 100%
1 parent 70d7abb commit c0441d1

File tree

5 files changed

+61
-20
lines changed

5 files changed

+61
-20
lines changed

phpstan.neon

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
parameters:
22
level: max
3-
checkGenericClassInNonGenericObjectType: false
4-
checkMissingIterableValueType: false
3+
4+
ignoreErrors:
5+
# Bug in PHPStan? The error is "expects A, A given"
6+
- '#Parameter \#1 \$tokens of method phpDocumentor\\Reflection\\Types\\ContextFactory::parse#'
7+
# ArrayIterator::current can return null if iterated even if ArrayIterator::valid isn't checked before
8+
- '#Strict comparison using === between array\(int, string, int\)\|string and false will always evaluate to false#'
9+
- '#Strict comparison using === between string and null will always evaluate to false#'
10+
- '#Unreachable statement - code above always terminates#'

psalm.xml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0"?>
22
<psalm
3-
totallyTyped="false"
3+
totallyTyped="true"
44
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
55
xmlns="https://getpsalm.org/schema/config"
66
xsi:schemaLocation="https://getpsalm.org/schema/config file:///composer/vendor/vimeo/psalm/config.xsd"
@@ -13,6 +13,20 @@
1313
</projectFiles>
1414

1515
<issueHandlers>
16-
<LessSpecificReturnType errorLevel="info" />
16+
<DocblockTypeContradiction>
17+
<errorLevel type="info">
18+
<!-- ArrayIterator::current can return null if iterated even if ArrayIterator::valid isn't checked before -->
19+
<file name="src/TypeResolver.php"/>
20+
<!-- Not sure what's going on. I don't think it's possible to have false here -->
21+
<file name="src/Types/ContextFactory.php"/>
22+
</errorLevel>
23+
</DocblockTypeContradiction>
24+
25+
<RedundantConditionGivenDocblockType>
26+
<errorLevel type="info">
27+
<!-- ArrayIterator::current can return null if iterated even if ArrayIterator::valid isn't checked before -->
28+
<file name="src/TypeResolver.php"/>
29+
</errorLevel>
30+
</RedundantConditionGivenDocblockType>
1731
</issueHandlers>
1832
</psalm>

src/TypeResolver.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ public function resolve(string $type, ?Context $context = null) : Type
151151
/**
152152
* Analyse each tokens and creates types
153153
*
154-
* @param ArrayIterator $tokens the iterator on tokens
155-
* @param int $parserContext on of self::PARSER_* constants, indicating
154+
* @param ArrayIterator<int, string> $tokens the iterator on tokens
155+
* @param int $parserContext on of self::PARSER_* constants, indicating
156156
* the context where we are in the parsing
157157
*/
158158
private function parseTypes(ArrayIterator $tokens, Context $context, int $parserContext) : Type
@@ -394,6 +394,8 @@ private function resolveTypedObject(string $type, ?Context $context = null) : Ob
394394

395395
/**
396396
* Resolves class string
397+
*
398+
* @param ArrayIterator<int, string> $tokens
397399
*/
398400
private function resolveClassString(ArrayIterator $tokens, Context $context) : Type
399401
{
@@ -425,6 +427,8 @@ private function resolveClassString(ArrayIterator $tokens, Context $context) : T
425427
/**
426428
* Resolves the collection values and keys
427429
*
430+
* @param ArrayIterator<int, string> $tokens
431+
*
428432
* @return Array_|Iterable_|Collection
429433
*/
430434
private function resolveCollection(ArrayIterator $tokens, Type $classType, Context $context) : Type

src/Types/Compound.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,20 @@
2424
* A Compound Type is not so much a special keyword or object reference but is a series of Types that are separated
2525
* using an OR operator (`|`). This combination of types signifies that whatever is associated with this compound type
2626
* may contain a value with any of the given types.
27+
*
28+
* @template-implements IteratorAggregate<int, Type>
2729
*/
2830
final class Compound implements Type, IteratorAggregate
2931
{
30-
/** @var Type[] */
32+
/** @var array<int, Type> */
3133
private $types = [];
3234

3335
/**
3436
* Initializes a compound type (i.e. `string|int`) and tests if the provided types all implement the Type interface.
3537
*
3638
* @param Type[] $types
39+
*
40+
* @phpstan-param list<Type> $types
3741
*/
3842
public function __construct(array $types)
3943
{
@@ -86,9 +90,9 @@ public function __toString() : string
8690
}
8791

8892
/**
89-
* {@inheritdoc}
93+
* @return ArrayIterator<int, Type>
9094
*/
91-
public function getIterator()
95+
public function getIterator() : ArrayIterator
9296
{
9397
return new ArrayIterator($this->types);
9498
}

src/Types/ContextFactory.php

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ final class ContextFactory
6464
public function createFromReflector(Reflector $reflector) : Context
6565
{
6666
if ($reflector instanceof ReflectionClass) {
67+
/** @var ReflectionClass<object> $reflector */
6768
return $this->createFromReflectionClass($reflector);
6869
}
6970

@@ -90,6 +91,7 @@ private function createFromReflectionParameter(ReflectionParameter $parameter) :
9091
{
9192
$class = $parameter->getDeclaringClass();
9293
if ($class) {
94+
/** @var ReflectionClass<object> $class */
9395
return $this->createFromReflectionClass($class);
9496
}
9597

@@ -111,6 +113,9 @@ private function createFromReflectionClassConstant(ReflectionClassConstant $cons
111113
return $this->createFromReflectionClass($constant->getDeclaringClass());
112114
}
113115

116+
/**
117+
* @param ReflectionClass<object> $class
118+
*/
114119
private function createFromReflectionClass(ReflectionClass $class) : Context
115120
{
116121
$fileName = $class->getFileName();
@@ -188,6 +193,8 @@ public function createForNamespace(string $namespace, string $fileContents) : Co
188193

189194
/**
190195
* Deduce the name from tokens when we are at the T_NAMESPACE token.
196+
*
197+
* @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
191198
*/
192199
private function parseNamespace(ArrayIterator $tokens) : string
193200
{
@@ -207,6 +214,8 @@ private function parseNamespace(ArrayIterator $tokens) : string
207214
/**
208215
* Deduce the names of all imports when we are at the T_USE token.
209216
*
217+
* @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
218+
*
210219
* @return string[]
211220
*/
212221
private function parseUseStatement(ArrayIterator $tokens) : array
@@ -231,6 +240,8 @@ private function parseUseStatement(ArrayIterator $tokens) : array
231240

232241
/**
233242
* Fast-forwards the iterator as longs as we don't encounter a T_STRING or T_NS_SEPARATOR token.
243+
*
244+
* @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
234245
*/
235246
private function skipToNextStringOrNamespaceSeparator(ArrayIterator $tokens) : void
236247
{
@@ -243,6 +254,8 @@ private function skipToNextStringOrNamespaceSeparator(ArrayIterator $tokens) : v
243254
* Deduce the namespace name and alias of an import when we are at the T_USE token or have not reached the end of
244255
* a USE statement yet. This will return a key/value array of the alias => namespace.
245256
*
257+
* @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
258+
*
246259
* @return string[]
247260
*
248261
* @psalm-suppress TypeDoesNotContainType
@@ -264,7 +277,7 @@ private function extractUseStatements(ArrayIterator $tokens) : array
264277
switch ($tokenId) {
265278
case T_STRING:
266279
case T_NS_SEPARATOR:
267-
$currentNs .= $tokenValue;
280+
$currentNs .= (string) $tokenValue;
268281
$currentAlias = $tokenValue;
269282
break;
270283
case T_CURLY_OPEN:
@@ -300,17 +313,17 @@ private function extractUseStatements(ArrayIterator $tokens) : array
300313
switch ($tokenId) {
301314
case T_STRING:
302315
case T_NS_SEPARATOR:
303-
$currentNs .= $tokenValue;
316+
$currentNs .= (string) $tokenValue;
304317
$currentAlias = $tokenValue;
305318
break;
306319
case T_AS:
307320
$state = 'grouped-alias';
308321
break;
309322
case self::T_LITERAL_USE_SEPARATOR:
310-
$state = 'grouped';
311-
$extractedUseStatements[$currentAlias] = $currentNs;
312-
$currentNs = $groupedNs;
313-
$currentAlias = '';
323+
$state = 'grouped';
324+
$extractedUseStatements[(string) $currentAlias] = $currentNs;
325+
$currentNs = $groupedNs;
326+
$currentAlias = '';
314327
break;
315328
case self::T_LITERAL_END_OF_USE:
316329
$state = 'end';
@@ -325,10 +338,10 @@ private function extractUseStatements(ArrayIterator $tokens) : array
325338
$currentAlias = $tokenValue;
326339
break;
327340
case self::T_LITERAL_USE_SEPARATOR:
328-
$state = 'grouped';
329-
$extractedUseStatements[$currentAlias] = $currentNs;
330-
$currentNs = $groupedNs;
331-
$currentAlias = '';
341+
$state = 'grouped';
342+
$extractedUseStatements[(string) $currentAlias] = $currentNs;
343+
$currentNs = $groupedNs;
344+
$currentAlias = '';
332345
break;
333346
case self::T_LITERAL_END_OF_USE:
334347
$state = 'end';
@@ -346,7 +359,7 @@ private function extractUseStatements(ArrayIterator $tokens) : array
346359
}
347360

348361
if ($groupedNs !== $currentNs) {
349-
$extractedUseStatements[$currentAlias] = $currentNs;
362+
$extractedUseStatements[(string) $currentAlias] = $currentNs;
350363
}
351364

352365
return $extractedUseStatements;

0 commit comments

Comments
 (0)