Skip to content

Commit a5f9f0c

Browse files
committed
Report only relevant unable to resolve template type message
1 parent 959b6e9 commit a5f9f0c

7 files changed

Lines changed: 86 additions & 10 deletions

File tree

src/Reflection/ResolvedFunctionVariant.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ public function __construct(
2828
$this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap;
2929
}
3030

31+
public function getOriginalParametersAcceptor(): ParametersAcceptor
32+
{
33+
return $this->parametersAcceptor;
34+
}
35+
3136
public function getTemplateTypeMap(): TemplateTypeMap
3237
{
3338
return $this->parametersAcceptor->getTemplateTypeMap();

src/Rules/FunctionCallParametersCheck.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Php\PhpVersion;
88
use PHPStan\Reflection\ParametersAcceptor;
9+
use PHPStan\Reflection\ResolvedFunctionVariant;
910
use PHPStan\Type\ErrorType;
11+
use PHPStan\Type\Generic\TemplateType;
1012
use PHPStan\Type\NeverType;
1113
use PHPStan\Type\Type;
1214
use PHPStan\Type\TypeCombinator;
15+
use PHPStan\Type\TypeTraverser;
1316
use PHPStan\Type\TypeUtils;
1417
use PHPStan\Type\VerbosityLevel;
1518
use PHPStan\Type\VoidType;
@@ -295,12 +298,27 @@ static function (Type $type): bool {
295298
))->line($argumentLine)->build();
296299
}
297300

298-
if ($this->checkMissingTypehints) {
301+
if ($this->checkMissingTypehints && $parametersAcceptor instanceof ResolvedFunctionVariant) {
302+
$originalReturnType = $parametersAcceptor->getOriginalParametersAcceptor()->getReturnType();
303+
$returnTemplateTypes = [];
304+
TypeTraverser::map($originalReturnType, static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Type {
305+
if ($type instanceof TemplateType) {
306+
$returnTemplateTypes[$type->getName()] = true;
307+
return $type;
308+
}
309+
310+
return $traverse($type);
311+
});
312+
299313
foreach ($parametersAcceptor->getResolvedTemplateTypeMap()->getTypes() as $name => $type) {
300314
if (!($type instanceof ErrorType) && !($type instanceof NeverType)) {
301315
continue;
302316
}
303317

318+
if (!array_key_exists($name, $returnTemplateTypes)) {
319+
continue;
320+
}
321+
304322
$errors[] = RuleErrorBuilder::message(sprintf($messages[9], $name))->line($funcCall->getLine())->build();
305323
}
306324
}

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,6 @@ public function testGenericFunction(): void
426426
'Unable to resolve the template type A in call to function CallGenericFunction\f',
427427
15,
428428
],
429-
[
430-
'Unable to resolve the template type B in call to function CallGenericFunction\f',
431-
15,
432-
],
433429
[
434430
'Parameter #1 $a of function CallGenericFunction\g expects DateTime, DateTimeImmutable given.',
435431
26,

tests/PHPStan/Rules/Functions/data/call-generic-function.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
* @template B
88
* @param int|array<A> $a
99
* @param int|array<B> $b
10+
* @return A[]
1011
*/
11-
function f($a, $b): void {
12-
}
12+
function f($a, $b): array {}
1313

1414
function test(): void {
1515
f(1, 2);
@@ -18,9 +18,9 @@ function test(): void {
1818
/**
1919
* @template A of \DateTime
2020
* @param A $a
21+
* @return A
2122
*/
22-
function g($a): void {
23-
}
23+
function g($a) {}
2424

2525
function testg(): void {
2626
g(new \DateTimeImmutable());

tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,4 +1750,17 @@ public function testBug4188(): void
17501750
$this->analyse([__DIR__ . '/data/bug-4188.php'], []);
17511751
}
17521752

1753+
public function testOnlyRelevantUnableToResolveTemplateType(): void
1754+
{
1755+
$this->checkThisOnly = false;
1756+
$this->checkNullables = true;
1757+
$this->checkUnionTypes = true;
1758+
$this->analyse([__DIR__ . '/data/only-relevant-unable-to-resolve-template-type.php'], [
1759+
[
1760+
'Unable to resolve the template type T in call to method OnlyRelevantUnableToResolve\Foo::doBaz()',
1761+
41,
1762+
],
1763+
]);
1764+
}
1765+
17531766
}

tests/PHPStan/Rules/Methods/data/call-methods.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1477,10 +1477,10 @@ class ClassStringWithUpperBounds
14771477
* @template T of \Exception
14781478
* @param class-string<T> $s
14791479
* @param T $object
1480+
* @return T
14801481
*/
14811482
public function doFoo(string $s, $object)
14821483
{
1483-
14841484
}
14851485

14861486
public function doBar(\Throwable $t)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace OnlyRelevantUnableToResolve;
4+
5+
class Foo
6+
{
7+
8+
/**
9+
* @template T
10+
* @param T $a
11+
* @return T[]
12+
*/
13+
public function doFoo($a)
14+
{
15+
16+
}
17+
18+
/**
19+
* @template T
20+
* @return int[]
21+
*/
22+
public function doBar()
23+
{
24+
25+
}
26+
27+
/**
28+
* @template T
29+
* @template U
30+
* @return T
31+
*/
32+
public function doBaz()
33+
{
34+
35+
}
36+
37+
public function doLorem()
38+
{
39+
$this->doFoo(1);
40+
$this->doBar();
41+
$this->doBaz();
42+
}
43+
44+
}

0 commit comments

Comments
 (0)