Skip to content

Commit e7138ad

Browse files
JanTvrdikondrejmirtes
authored andcommitted
improve handling of unresolvable types in PHPDoc
1 parent 0845efd commit e7138ad

File tree

6 files changed

+98
-14
lines changed

6 files changed

+98
-14
lines changed

Diff for: src/Rules/PhpDoc/IncompatiblePhpDocTypeRule.php

+24-13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Type\ArrayType;
8+
use PHPStan\Type\ErrorType;
89
use PHPStan\Type\FileTypeMapper;
910
use PHPStan\Type\Type;
1011

@@ -54,6 +55,12 @@ public function processNode(Node $node, Scope $scope): array
5455
$parameterName
5556
);
5657

58+
} elseif ($phpDocParamType instanceof ErrorType) {
59+
$errors[] = sprintf(
60+
'PHPDoc tag @param for parameter $%s contains unresolvable type',
61+
$parameterName
62+
);
63+
5764
} else {
5865
$nativeParamType = $nativeParameterTypes[$parameterName];
5966
$isParamSuperType = $nativeParamType->isSuperTypeOf($phpDocParamType);
@@ -88,21 +95,25 @@ public function processNode(Node $node, Scope $scope): array
8895
if ($resolvedPhpDoc->getReturnTag() !== null) {
8996
$phpDocReturnType = $resolvedPhpDoc->getReturnTag()->getType();
9097

91-
$isReturnSuperType = $nativeReturnType->isSuperTypeOf($phpDocReturnType);
98+
if ($phpDocReturnType instanceof ErrorType) {
99+
$errors[] = 'PHPDoc tag @return contains unresolvable type';
92100

93-
if ($isReturnSuperType->no()) {
94-
$errors[] = sprintf(
95-
'PHPDoc tag @return with type %s is incompatible with native type %s',
96-
$phpDocReturnType->describe(),
97-
$nativeReturnType->describe()
98-
);
101+
} else {
102+
$isReturnSuperType = $nativeReturnType->isSuperTypeOf($phpDocReturnType);
103+
if ($isReturnSuperType->no()) {
104+
$errors[] = sprintf(
105+
'PHPDoc tag @return with type %s is incompatible with native type %s',
106+
$phpDocReturnType->describe(),
107+
$nativeReturnType->describe()
108+
);
99109

100-
} elseif ($isReturnSuperType->maybe()) {
101-
$errors[] = sprintf(
102-
'PHPDoc tag @return with type %s is not subtype of native type %s',
103-
$phpDocReturnType->describe(),
104-
$nativeReturnType->describe()
105-
);
110+
} elseif ($isReturnSuperType->maybe()) {
111+
$errors[] = sprintf(
112+
'PHPDoc tag @return with type %s is not subtype of native type %s',
113+
$phpDocReturnType->describe(),
114+
$nativeReturnType->describe()
115+
);
116+
}
106117
}
107118
}
108119

Diff for: src/Type/TypehintHelper.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static function decideType(
7676
Type $phpDocType = null
7777
): Type
7878
{
79-
if ($phpDocType !== null) {
79+
if ($phpDocType !== null && !$phpDocType instanceof ErrorType) {
8080
if ($type instanceof VoidType || $phpDocType instanceof VoidType) {
8181
return new VoidType();
8282
}

Diff for: tests/PHPStan/Analyser/NodeScopeResolverTest.php

+35
Original file line numberDiff line numberDiff line change
@@ -3653,6 +3653,41 @@ public function testMisleadingTypesWithoutNamespace(
36533653
);
36543654
}
36553655

3656+
public function dataUnresolvableTypes(): array
3657+
{
3658+
return [
3659+
[
3660+
'mixed',
3661+
'$arrayWithTooManyArgs',
3662+
],
3663+
[
3664+
'mixed',
3665+
'$iterableWithTooManyArgs',
3666+
],
3667+
[
3668+
'mixed',
3669+
'$genericFoo',
3670+
],
3671+
];
3672+
}
3673+
3674+
/**
3675+
* @dataProvider dataUnresolvableTypes
3676+
* @param string $description
3677+
* @param string $expression
3678+
*/
3679+
public function testUnresolvableTypes(
3680+
string $description,
3681+
string $expression
3682+
)
3683+
{
3684+
$this->assertTypes(
3685+
__DIR__ . '/data/unresolvable-types.php',
3686+
$description,
3687+
$expression
3688+
);
3689+
}
3690+
36563691
public function dataCombineTypes(): array
36573692
{
36583693
return [

Diff for: tests/PHPStan/Analyser/data/unresolvable-types.php

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace UnresolvableTypes;
4+
5+
/**
6+
* @param array<int, int, int> $arrayWithTooManyArgs
7+
* @param iterable<int, int, int> $iterableWithTooManyArgs
8+
* @param \Foo<int> $genericFoo
9+
*/
10+
function test(
11+
$arrayWithTooManyArgs,
12+
$iterableWithTooManyArgs,
13+
$genericFoo
14+
) {
15+
die;
16+
}

Diff for: tests/PHPStan/Rules/PhpDoc/IncompatiblePhpDocTypeRuleTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ public function testRule()
4545
'PHPDoc tag @param for parameter $numbers with type array<int, string> is incompatible with native type array<int, int>',
4646
99,
4747
],
48+
[
49+
'PHPDoc tag @param for parameter $arr contains unresolvable type',
50+
117,
51+
],
52+
[
53+
'PHPDoc tag @param references unknown parameter $arrX',
54+
117,
55+
],
56+
[
57+
'PHPDoc tag @return contains unresolvable type',
58+
117,
59+
],
4860
]);
4961
}
5062

Diff for: tests/PHPStan/Rules/PhpDoc/data/incompatible-types.php

+10
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,13 @@ function variadicStringArrays(array ...$strings)
108108
{
109109

110110
}
111+
112+
/**
113+
* @param array<int, int, int> $arr
114+
* @param array<int, int, int> $arrX
115+
* @return bool <strong>true</strong> or <strong>false</strong>
116+
*/
117+
function unresolvableTypes(array $arr): bool
118+
{
119+
120+
}

0 commit comments

Comments
 (0)