Skip to content

Commit 7833bc7

Browse files
paxalondrejmirtes
authored andcommitted
Feature: support typehints in function signature
1 parent 6430c61 commit 7833bc7

File tree

5 files changed

+179
-0
lines changed

5 files changed

+179
-0
lines changed

rules.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ rules:
99
- PHPStan\Rules\Deprecations\InheritanceOfDeprecatedClassRule
1010
- PHPStan\Rules\Deprecations\InheritanceOfDeprecatedInterfaceRule
1111
- PHPStan\Rules\Deprecations\InstantiationOfDeprecatedClassRule
12+
- PHPStan\Rules\Deprecations\TypeHintDeprecatedInFunctionSignatureRule
1213
- PHPStan\Rules\Deprecations\UsageOfDeprecatedTraitRule
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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\Broker\Broker;
8+
9+
class TypeHintDeprecatedInFunctionSignatureRule implements \PHPStan\Rules\Rule
10+
{
11+
12+
/** @var Broker */
13+
private $broker;
14+
15+
public function __construct(Broker $broker)
16+
{
17+
$this->broker = $broker;
18+
}
19+
20+
public function getNodeType(): string
21+
{
22+
return Node\FunctionLike::class;
23+
}
24+
25+
/**
26+
* @param Node\FunctionLike $node
27+
* @param \PHPStan\Analyser\Scope $scope
28+
* @return string[] errors
29+
*/
30+
public function processNode(Node $node, Scope $scope): array
31+
{
32+
$errors = [];
33+
foreach ($node->getParams() as $i => $param) {
34+
$className = $this->getClassName($param->type, $scope);
35+
if ($className === null) {
36+
continue;
37+
}
38+
39+
$errors[] = $this->checkClasses($className, 'argument #' . $i);
40+
}
41+
42+
$className = $this->getClassName($node->getReturnType(), $scope);
43+
if ($className !== null) {
44+
$errors[] = $this->checkClasses($className, 'return type');
45+
}
46+
47+
return array_filter($errors);
48+
}
49+
50+
/**
51+
* @param null|Node\Name|Node\Identifier|Node\NullableType $type
52+
* @param Scope $scope
53+
* @return string|null
54+
*/
55+
private function getClassName($type, Scope $scope): ?string
56+
{
57+
if ($type instanceof Node\NullableType) {
58+
return $this->getClassName($type->type, $scope);
59+
}
60+
61+
if ($type instanceof Node\Name) {
62+
return $scope->resolveName($type);
63+
}
64+
65+
if ($type instanceof Node\Identifier) {
66+
return null;
67+
}
68+
69+
return null;
70+
}
71+
72+
73+
private function checkClasses(string $referencedClass, string $where): ?string
74+
{
75+
try {
76+
$class = $this->broker->getClass($referencedClass);
77+
} catch (\PHPStan\Broker\ClassNotFoundException $e) {
78+
return null;
79+
}
80+
81+
if ($class->isDeprecated()) {
82+
$classDescription = null;
83+
if (method_exists($class, 'getDeprecatedDescription')) {
84+
$classDescription = $class->getDeprecatedDescription();
85+
}
86+
87+
if ($classDescription === null) {
88+
return sprintf(
89+
'Usage of deprecated class %s in %s.',
90+
$referencedClass,
91+
$where
92+
);
93+
}
94+
95+
return sprintf(
96+
"Usage of deprecated class %s in %s:\n%s",
97+
$referencedClass,
98+
$where,
99+
$classDescription
100+
);
101+
}
102+
103+
return null;
104+
}
105+
106+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Deprecations;
4+
5+
class TypeHintDeprecatedInFunctionSignatureRuleTest extends \PHPStan\Testing\RuleTestCase
6+
{
7+
8+
protected function getRule(): \PHPStan\Rules\Rule
9+
{
10+
$broker = $this->createBroker();
11+
12+
return new TypeHintDeprecatedInFunctionSignatureRule($broker);
13+
}
14+
15+
public function test(): void
16+
{
17+
require_once __DIR__ . '/data/typehint-deprecated-class-definition.php';
18+
$this->analyse(
19+
[__DIR__ . '/data/typehint-deprecated-class.php'],
20+
[
21+
['Usage of deprecated class TypeHintDeprecatedInFunctionSignature\DeprecatedProperty in argument #0.', 10],
22+
['Usage of deprecated class TypeHintDeprecatedInFunctionSignature\DeprecatedProperty in argument #1.', 10],
23+
['Usage of deprecated class TypeHintDeprecatedInFunctionSignature\DeprecatedProperty in return type.', 10],
24+
]
25+
);
26+
}
27+
28+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace TypeHintDeprecatedInFunctionSignature;
4+
5+
/**
6+
* @deprecated
7+
*/
8+
class DeprecatedProperty
9+
{
10+
11+
}
12+
13+
class Property
14+
{
15+
16+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace TypeHintDeprecatedInFunctionSignature;
4+
5+
class Foo
6+
{
7+
8+
private $properties;
9+
10+
public function setProperties(
11+
DeprecatedProperty $property,
12+
?DeprecatedProperty $property2,
13+
$property3,
14+
Property $property4,
15+
string $property5
16+
): DeprecatedProperty {
17+
$this->properties = [
18+
$property,
19+
$property2,
20+
$property3,
21+
$property4,
22+
$property5,
23+
];
24+
25+
return $property;
26+
}
27+
28+
}

0 commit comments

Comments
 (0)