Skip to content

Commit c46b4ac

Browse files
adaamzondrejmirtes
authored andcommitted
Check whether function parameter has typehint
1 parent b1040c9 commit c46b4ac

File tree

5 files changed

+133
-1
lines changed

5 files changed

+133
-1
lines changed

composer.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
}
3030
},
3131
"autoload-dev": {
32-
"classmap": ["tests/"]
32+
"classmap": ["tests/"],
33+
"files": [
34+
"tests/Rules/Functions/data/missing-function-parameter-typehint.php"
35+
]
3336
}
3437
}

rules.neon

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ rules:
1414
- PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule
1515
- PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule
1616
- PHPStan\Rules\DisallowedConstructs\DisallowedImplicitArrayCreationRule
17+
- PHPStan\Rules\Functions\MissingFunctionParameterTypehintRule
1718
- PHPStan\Rules\Methods\MissingMethodParameterTypehintRule
1819
- PHPStan\Rules\Methods\MissingMethodReturnTypehintRule
1920
- PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Functions;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Broker\Broker;
8+
use PHPStan\Reflection\FunctionReflection;
9+
use PHPStan\Reflection\ParameterReflection;
10+
use PHPStan\Reflection\ParametersAcceptorSelector;
11+
use PHPStan\Type\MixedType;
12+
13+
final class MissingFunctionParameterTypehintRule implements \PHPStan\Rules\Rule
14+
{
15+
16+
/** @var Broker */
17+
private $broker;
18+
19+
public function __construct(Broker $broker)
20+
{
21+
$this->broker = $broker;
22+
}
23+
24+
public function getNodeType(): string
25+
{
26+
return \PhpParser\Node\Stmt\Function_::class;
27+
}
28+
29+
/**
30+
* @param \PhpParser\Node\Stmt\Function_ $node
31+
* @param \PHPStan\Analyser\Scope $scope
32+
*
33+
* @return string[] errors
34+
*/
35+
public function processNode(Node $node, Scope $scope): array
36+
{
37+
$functionReflection = $this->broker->getCustomFunction(new Node\Name($node->name->name), $scope);
38+
39+
$messages = [];
40+
41+
foreach (ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getParameters() as $parameterReflection) {
42+
$message = $this->checkFunctionParameter($functionReflection, $parameterReflection);
43+
if ($message === null) {
44+
continue;
45+
}
46+
47+
$messages[] = $message;
48+
}
49+
50+
return $messages;
51+
}
52+
53+
private function checkFunctionParameter(FunctionReflection $functionReflection, ParameterReflection $parameterReflection): ?string
54+
{
55+
$parameterType = $parameterReflection->getType();
56+
57+
if ($parameterType instanceof MixedType && !$parameterType->isExplicitMixed()) {
58+
return sprintf(
59+
'Function %s() has parameter $%s with no typehint specified.',
60+
$functionReflection->getName(),
61+
$parameterReflection->getName()
62+
);
63+
}
64+
65+
return null;
66+
}
67+
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Functions;
4+
5+
class MissingFunctionParameterTypehintRuleTest extends \PHPStan\Testing\RuleTestCase
6+
{
7+
8+
protected function getRule(): \PHPStan\Rules\Rule
9+
{
10+
$rule = new MissingFunctionParameterTypehintRule($this->createBroker([], []));
11+
12+
return $rule;
13+
}
14+
15+
public function testRule(): void
16+
{
17+
$this->analyse([__DIR__ . '/data/missing-function-parameter-typehint.php'], [
18+
[
19+
'Function globalFunction() has parameter $b with no typehint specified.',
20+
9,
21+
],
22+
[
23+
'Function globalFunction() has parameter $c with no typehint specified.',
24+
9,
25+
],
26+
[
27+
'Function MissingFunctionParameterTypehint\namespacedFunction() has parameter $d with no typehint specified.',
28+
24,
29+
],
30+
]);
31+
}
32+
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace
4+
{
5+
/**
6+
* @param int $a
7+
* @param $b
8+
*/
9+
function globalFunction($a, $b, $c): bool
10+
{
11+
$closure = function($a, $b, $c) {
12+
13+
};
14+
15+
return false;
16+
}
17+
}
18+
19+
namespace MissingFunctionParameterTypehint
20+
{
21+
/**
22+
* @param $d
23+
*/
24+
function namespacedFunction($d, bool $e): int {
25+
return 9;
26+
};
27+
}

0 commit comments

Comments
 (0)