Skip to content

Commit

Permalink
ParameterOutAssignedTypeRule - adjust for reading the by-ref type if …
Browse files Browse the repository at this point in the history
…`@param-out` is not present
  • Loading branch information
ondrejmirtes committed Feb 25, 2024
1 parent 1dfe218 commit 2f55c7c
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 18 deletions.
33 changes: 21 additions & 12 deletions src/Rules/Variables/ParameterOutAssignedTypeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,26 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

if ($foundParameter->getOutType() === null) {
return [];
$isParamOutType = true;
$outType = $foundParameter->getOutType();
if ($outType === null) {
$isParamOutType = false;
$outType = $foundParameter->getType();
}

$typeResult = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$node->getAssignedExpr(),
'',
static fn (Type $type): bool => $foundParameter->getOutType()->isSuperTypeOf($type)->yes(),
static fn (Type $type): bool => $outType->isSuperTypeOf($type)->yes(),
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
return $typeResult->getUnknownClassErrors();
}

$assignedExprType = $scope->getType($node->getAssignedExpr());
if ($foundParameter->getOutType()->isSuperTypeOf($assignedExprType)->yes()) {
if ($outType->isSuperTypeOf($assignedExprType)->yes()) {
return [];
}

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

$verbosityLevel = VerbosityLevel::getRecommendedLevelByType($foundParameter->getOutType(), $assignedExprType);
$verbosityLevel = VerbosityLevel::getRecommendedLevelByType($outType, $assignedExprType);
$errorBuilder = RuleErrorBuilder::message(sprintf(
'Parameter &$%s %s of %s expects %s, %s given.',
$foundParameter->getName(),
$isParamOutType ? '@param-out type' : 'by-ref type',
$functionDescription,
$outType->describe($verbosityLevel),
$assignedExprType->describe($verbosityLevel),
));

if (!$isParamOutType) {
$errorBuilder->tip('You can change the parameter out type with @param-out PHPDoc tag.');
}

return [
RuleErrorBuilder::message(sprintf(
'Parameter &$%s out type of %s expects %s, %s given.',
$foundParameter->getName(),
$functionDescription,
$foundParameter->getOutType()->describe($verbosityLevel),
$assignedExprType->describe($verbosityLevel),
))->build(),
$errorBuilder->build(),
];
}

Expand Down
17 changes: 11 additions & 6 deletions tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,34 @@ public function testRule(): void
{
$this->analyse([__DIR__ . '/data/parameter-out-assigned-type.php'], [
[
'Parameter &$p out type of function ParameterOutAssignedType\foo() expects int, string given.',
'Parameter &$p @param-out type of function ParameterOutAssignedType\foo() expects int, string given.',
10,
],
[
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doFoo() expects int, string given.',
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doFoo() expects int, string given.',
21,
],
[
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBar() expects string, int given.',
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBar() expects string, int given.',
29,
],
[
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBaz() expects list<int>, array<0|int<2, max>, int> given.',
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBaz() expects list<int>, array<0|int<2, max>, int> given.',
38,
],
[
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBaz2() expects list<int>, non-empty-list<\'str\'|int> given.',
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBaz2() expects list<int>, non-empty-list<\'str\'|int> given.',
47,
],
[
'Parameter &$p out type of method ParameterOutAssignedType\Foo::doBaz3() expects list<list<int>>, array<int<0, max>, array<int<0, max>, int>> given.',
'Parameter &$p @param-out type of method ParameterOutAssignedType\Foo::doBaz3() expects list<list<int>>, array<int<0, max>, array<int<0, max>, int>> given.',
56,
],
[
'Parameter &$p by-ref type of method ParameterOutAssignedType\Foo::doNoParamOut() expects string, int given.',
61,
'You can change the parameter out type with @param-out PHPDoc tag.',
],
]);
}

Expand Down
10 changes: 10 additions & 0 deletions tests/PHPStan/Rules/Variables/data/parameter-out-assigned-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,14 @@ function doBaz3(&$p): void
unset($p[1][2]);
}

function doNoParamOut(string &$p): void
{
$p = 1;
}

function doNoParamOut2(string &$p): void
{
$p = 'foo';
}

}

0 comments on commit 2f55c7c

Please sign in to comment.