Skip to content

Commit 2f55c7c

Browse files
committed
ParameterOutAssignedTypeRule - adjust for reading the by-ref type if @param-out is not present
1 parent 1dfe218 commit 2f55c7c

File tree

3 files changed

+42
-18
lines changed

3 files changed

+42
-18
lines changed

src/Rules/Variables/ParameterOutAssignedTypeRule.php

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,23 +68,26 @@ public function processNode(Node $node, Scope $scope): array
6868
return [];
6969
}
7070

71-
if ($foundParameter->getOutType() === null) {
72-
return [];
71+
$isParamOutType = true;
72+
$outType = $foundParameter->getOutType();
73+
if ($outType === null) {
74+
$isParamOutType = false;
75+
$outType = $foundParameter->getType();
7376
}
7477

7578
$typeResult = $this->ruleLevelHelper->findTypeToCheck(
7679
$scope,
7780
$node->getAssignedExpr(),
7881
'',
79-
static fn (Type $type): bool => $foundParameter->getOutType()->isSuperTypeOf($type)->yes(),
82+
static fn (Type $type): bool => $outType->isSuperTypeOf($type)->yes(),
8083
);
8184
$type = $typeResult->getType();
8285
if ($type instanceof ErrorType) {
8386
return $typeResult->getUnknownClassErrors();
8487
}
8588

8689
$assignedExprType = $scope->getType($node->getAssignedExpr());
87-
if ($foundParameter->getOutType()->isSuperTypeOf($assignedExprType)->yes()) {
90+
if ($outType->isSuperTypeOf($assignedExprType)->yes()) {
8891
return [];
8992
}
9093

@@ -94,16 +97,22 @@ public function processNode(Node $node, Scope $scope): array
9497
$functionDescription = sprintf('function %s()', $inFunction->getName());
9598
}
9699

97-
$verbosityLevel = VerbosityLevel::getRecommendedLevelByType($foundParameter->getOutType(), $assignedExprType);
100+
$verbosityLevel = VerbosityLevel::getRecommendedLevelByType($outType, $assignedExprType);
101+
$errorBuilder = RuleErrorBuilder::message(sprintf(
102+
'Parameter &$%s %s of %s expects %s, %s given.',
103+
$foundParameter->getName(),
104+
$isParamOutType ? '@param-out type' : 'by-ref type',
105+
$functionDescription,
106+
$outType->describe($verbosityLevel),
107+
$assignedExprType->describe($verbosityLevel),
108+
));
109+
110+
if (!$isParamOutType) {
111+
$errorBuilder->tip('You can change the parameter out type with @param-out PHPDoc tag.');
112+
}
98113

99114
return [
100-
RuleErrorBuilder::message(sprintf(
101-
'Parameter &$%s out type of %s expects %s, %s given.',
102-
$foundParameter->getName(),
103-
$functionDescription,
104-
$foundParameter->getOutType()->describe($verbosityLevel),
105-
$assignedExprType->describe($verbosityLevel),
106-
))->build(),
115+
$errorBuilder->build(),
107116
];
108117
}
109118

tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,34 @@ public function testRule(): void
2323
{
2424
$this->analyse([__DIR__ . '/data/parameter-out-assigned-type.php'], [
2525
[
26-
'Parameter &$p out type of function ParameterOutAssignedType\foo() expects int, string given.',
26+
'Parameter &$p @param-out type of function ParameterOutAssignedType\foo() expects int, string given.',
2727
10,
2828
],
2929
[
30-
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doFoo() expects int, string given.',
30+
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doFoo() expects int, string given.',
3131
21,
3232
],
3333
[
34-
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBar() expects string, int given.',
34+
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBar() expects string, int given.',
3535
29,
3636
],
3737
[
38-
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBaz() expects list<int>, array<0|int<2, max>, int> given.',
38+
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBaz() expects list<int>, array<0|int<2, max>, int> given.',
3939
38,
4040
],
4141
[
42-
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBaz2() expects list<int>, non-empty-list<\'str\'|int> given.',
42+
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBaz2() expects list<int>, non-empty-list<\'str\'|int> given.',
4343
47,
4444
],
4545
[
46-
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBaz3() expects list<list<int>>, array<int<0, max>, array<int<0, max>, int>> given.',
46+
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBaz3() expects list<list<int>>, array<int<0, max>, array<int<0, max>, int>> given.',
4747
56,
4848
],
49+
[
50+
'Parameter &$p by-ref type of method ParameterOutAssignedType\Foo::doNoParamOut() expects string, int given.',
51+
61,
52+
'You can change the parameter out type with @param-out PHPDoc tag.',
53+
],
4954
]);
5055
}
5156

tests/PHPStan/Rules/Variables/data/parameter-out-assigned-type.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,14 @@ function doBaz3(&$p): void
5656
unset($p[1][2]);
5757
}
5858

59+
function doNoParamOut(string &$p): void
60+
{
61+
$p = 1;
62+
}
63+
64+
function doNoParamOut2(string &$p): void
65+
{
66+
$p = 'foo';
67+
}
68+
5969
}

0 commit comments

Comments
 (0)