Skip to content

Commit

Permalink
Allow undefined variables passed into by-ref parameters only if the t…
Browse files Browse the repository at this point in the history
…ype is nullable
  • Loading branch information
ondrejmirtes committed Apr 14, 2024
1 parent f71da02 commit 7f8f9cc
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 5 deletions.
22 changes: 17 additions & 5 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3797,6 +3797,7 @@ private function processArgs(
foreach ($args as $i => $arg) {
$assignByReference = false;
$parameter = null;
$parameterType = null;
if (isset($parameters) && $parametersAcceptor !== null) {
if (isset($parameters[$i])) {
$assignByReference = $parameters[$i]->passedByReference()->createsNewVariable();
Expand All @@ -3810,9 +3811,22 @@ private function processArgs(
}
}

$lookForUnset = false;
if ($assignByReference) {
if ($arg->value instanceof Variable) {
$scope = $this->lookForSetAllowedUndefinedExpressions($scope, $arg->value);
$isBuiltin = false;
if ($calleeReflection instanceof FunctionReflection && $calleeReflection->isBuiltin()) {
$isBuiltin = true;
} elseif ($calleeReflection instanceof ExtendedMethodReflection && $calleeReflection->getDeclaringClass()->isBuiltin()) {
$isBuiltin = true;
}
if (
$isBuiltin
|| ($parameterType === null || !$parameterType->isNull()->no())
) {
$scope = $this->lookForSetAllowedUndefinedExpressions($scope, $arg->value);
$lookForUnset = true;
}
}
}

Expand All @@ -3839,10 +3853,8 @@ private function processArgs(
$result = $this->processExprNode($stmt, $arg->value, $scopeToPass, $nodeCallback, $context->enterDeep());
}
$scope = $result->getScope();
if ($assignByReference) {
if ($arg->value instanceof Variable) {
$scope = $this->lookForUnsetAllowedUndefinedExpressions($scope, $arg->value);
}
if ($assignByReference && $lookForUnset) {
$scope = $this->lookForUnsetAllowedUndefinedExpressions($scope, $arg->value);
}

if ($calleeReflection !== null) {
Expand Down
18 changes: 18 additions & 0 deletions tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1042,4 +1042,22 @@ public function testBug10418(): void
$this->analyse([__DIR__ . '/data/bug-10418.php'], []);
}

public function testPassByReferenceIntoNotNullable(): void
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Test requires PHP 8.0.');
}

$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = true;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;
$this->analyse([__DIR__ . '/data/pass-by-reference-into-not-nullable.php'], [
[
'Undefined variable: $three',
32,
],
]);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php // lint >= 8.0

namespace PassByReferenceIntoNotNullable;

class Foo
{

public function doFooNoType(&$test)
{

}

public function doFooMixedType(mixed &$test)
{

}

public function doFooIntType(int &$test)
{

}

public function doFooNullableType(?int &$test)
{

}

public function test()
{
$this->doFooNoType($one);
$this->doFooMixedType($two);
$this->doFooIntType($three);
$this->doFooNullableType($four);
}

}

0 comments on commit 7f8f9cc

Please sign in to comment.