Skip to content

Commit 0887096

Browse files
paxalondrejmirtes
authored andcommitted
Add deprecation check for anonymous function typehints
1 parent ba6db34 commit 0887096

File tree

5 files changed

+145
-0
lines changed

5 files changed

+145
-0
lines changed

rules.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ rules:
1414
- PHPStan\Rules\Deprecations\InheritanceOfDeprecatedInterfaceRule
1515
- PHPStan\Rules\Deprecations\InstantiationOfDeprecatedClassRule
1616
- PHPStan\Rules\Deprecations\TypeHintDeprecatedInClassMethodSignatureRule
17+
- PHPStan\Rules\Deprecations\TypeHintDeprecatedInClosureSignatureRule
1718
- PHPStan\Rules\Deprecations\UsageOfDeprecatedTraitRule
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Deprecations;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Node\InClosureNode;
8+
use PHPStan\Node\InFunctionNode;
9+
use PHPStan\Reflection\ParametersAcceptor;
10+
11+
class TypeHintDeprecatedInClosureSignatureRule implements \PHPStan\Rules\Rule
12+
{
13+
14+
/** @var DeprecatedClassHelper */
15+
private $deprecatedClassHelper;
16+
17+
public function __construct(DeprecatedClassHelper $deprecatedClassHelper)
18+
{
19+
$this->deprecatedClassHelper = $deprecatedClassHelper;
20+
}
21+
22+
public function getNodeType(): string
23+
{
24+
return InClosureNode::class;
25+
}
26+
27+
/**
28+
* @param InFunctionNode $node
29+
* @param \PHPStan\Analyser\Scope $scope
30+
* @return string[] errors
31+
*/
32+
public function processNode(Node $node, Scope $scope): array
33+
{
34+
if (DeprecatedScopeHelper::isScopeDeprecated($scope)) {
35+
return [];
36+
}
37+
38+
$functionSignature = $scope->getAnonymousFunctionReflection();
39+
if (!$functionSignature instanceof ParametersAcceptor) {
40+
throw new \PHPStan\ShouldNotHappenException();
41+
}
42+
43+
$errors = [];
44+
foreach ($functionSignature->getParameters() as $i => $parameter) {
45+
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($parameter->getType()->getReferencedClasses());
46+
foreach ($deprecatedClasses as $deprecatedClass) {
47+
$errors[] = sprintf(
48+
'Parameter $%s of anonymous function has typehint with deprecated %s %s%s',
49+
$parameter->getName(),
50+
$this->deprecatedClassHelper->getClassType($deprecatedClass),
51+
$deprecatedClass->getName(),
52+
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
53+
);
54+
}
55+
}
56+
57+
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($functionSignature->getReturnType()->getReferencedClasses());
58+
foreach ($deprecatedClasses as $deprecatedClass) {
59+
$errors[] = sprintf(
60+
'Return type of anonymous function has typehint with deprecated %s %s%s',
61+
$this->deprecatedClassHelper->getClassType($deprecatedClass),
62+
$deprecatedClass->getName(),
63+
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
64+
);
65+
}
66+
67+
return $errors;
68+
}
69+
70+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Deprecations;
4+
5+
class TypeHintDeprecatedInClosureSignatureRuleTest extends \PHPStan\Testing\RuleTestCase
6+
{
7+
8+
protected function getRule(): \PHPStan\Rules\Rule
9+
{
10+
$broker = $this->createBroker();
11+
12+
return new TypeHintDeprecatedInClosureSignatureRule(new DeprecatedClassHelper($broker));
13+
}
14+
15+
public function test(): void
16+
{
17+
require_once __DIR__ . '/data/typehint-anonymous-function-deprecated-class-definition.php';
18+
$this->analyse(
19+
[__DIR__ . '/data/typehint-anonymous-function-deprecated-class.php'],
20+
[
21+
['Parameter $property of anonymous function has typehint with deprecated class TypeHintDeprecatedInClosureSignature\DeprecatedProperty.', 5],
22+
['Parameter $property2 of anonymous function has typehint with deprecated interface TypeHintDeprecatedInClosureSignature\DeprecatedInterface.', 5],
23+
["Parameter \$property4 of anonymous function has typehint with deprecated class TypeHintDeprecatedInClosureSignature\VerboseDeprecatedProperty:\nI'll be back", 5],
24+
['Return type of anonymous function has typehint with deprecated class TypeHintDeprecatedInClosureSignature\DeprecatedProperty.', 5],
25+
]
26+
);
27+
}
28+
29+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace TypeHintDeprecatedInClosureSignature;
4+
5+
/**
6+
* @deprecated
7+
*/
8+
class DeprecatedProperty
9+
{
10+
11+
}
12+
13+
/**
14+
* @deprecated I'll be back
15+
*/
16+
class VerboseDeprecatedProperty
17+
{
18+
19+
}
20+
21+
/**
22+
* @deprecated
23+
*/
24+
interface DeprecatedInterface
25+
{
26+
27+
}
28+
29+
class Property
30+
{
31+
32+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace TypeHintDeprecatedInClosureSignature;
4+
5+
$a = function (
6+
DeprecatedProperty $property,
7+
?DeprecatedInterface $property2,
8+
$property3,
9+
VerboseDeprecatedProperty $property4,
10+
string $property5
11+
): ?DeprecatedProperty {
12+
return $property;
13+
};

0 commit comments

Comments
 (0)