Skip to content

Commit c45d42d

Browse files
committed
Do not influence types of arguments before the function is called
1 parent 0b8dca7 commit c45d42d

File tree

2 files changed

+52
-24
lines changed

2 files changed

+52
-24
lines changed

src/Analyser/NodeScopeResolver.php

+48-24
Original file line numberDiff line numberDiff line change
@@ -3580,43 +3580,27 @@ private function processArgs(
35803580
$hasYield = false;
35813581
$throwPoints = [];
35823582
foreach ($args as $i => $arg) {
3583-
$originalArg = $arg->getAttribute(ArgumentsNormalizer::ORIGINAL_ARG_ATTRIBUTE) ?? $arg;
3584-
$nodeCallback($originalArg, $scope);
3583+
$assignByReference = false;
35853584
if (isset($parameters) && $parametersAcceptor !== null) {
3586-
$byRefType = new MixedType();
3587-
$assignByReference = false;
35883585
if (isset($parameters[$i])) {
35893586
$assignByReference = $parameters[$i]->passedByReference()->createsNewVariable();
35903587
$parameterType = $parameters[$i]->getType();
3591-
3592-
if (isset($paramOutTypes[$parameters[$i]->getName()])) {
3593-
$byRefType = $paramOutTypes[$parameters[$i]->getName()];
3594-
}
35953588
} elseif (count($parameters) > 0 && $parametersAcceptor->isVariadic()) {
35963589
$lastParameter = $parameters[count($parameters) - 1];
35973590
$assignByReference = $lastParameter->passedByReference()->createsNewVariable();
35983591
$parameterType = $lastParameter->getType();
3599-
3600-
if (isset($paramOutTypes[$lastParameter->getName()])) {
3601-
$byRefType = $paramOutTypes[$lastParameter->getName()];
3602-
}
36033592
}
3593+
}
36043594

3605-
if ($assignByReference) {
3606-
$argValue = $arg->value;
3607-
if ($argValue instanceof Variable && is_string($argValue->name)) {
3608-
$scope = $scope->assignVariable($argValue->name, $byRefType, new MixedType());
3609-
} else {
3610-
$scope = $scope->invalidateExpression($argValue);
3611-
}
3612-
} elseif ($calleeReflection !== null && $calleeReflection->hasSideEffects()->yes()) {
3613-
$argType = $scope->getType($arg->value);
3614-
if (!$argType->isObject()->no() || !(new ResourceType())->isSuperTypeOf($argType)->no()) {
3615-
$scope = $scope->invalidateExpression($arg->value, true);
3616-
}
3595+
if ($assignByReference) {
3596+
if ($arg->value instanceof Variable) {
3597+
$scope = $this->lookForSetAllowedUndefinedExpressions($scope, $arg->value);
36173598
}
36183599
}
36193600

3601+
$originalArg = $arg->getAttribute(ArgumentsNormalizer::ORIGINAL_ARG_ATTRIBUTE) ?? $arg;
3602+
$nodeCallback($originalArg, $scope);
3603+
36203604
$originalScope = $scope;
36213605
$scopeToPass = $scope;
36223606
if ($i === 0 && $closureBindScope !== null) {
@@ -3633,6 +3617,11 @@ private function processArgs(
36333617
$result = $this->processExprNode($arg->value, $scopeToPass, $nodeCallback, $context->enterDeep());
36343618
}
36353619
$scope = $result->getScope();
3620+
if ($assignByReference) {
3621+
if ($arg->value instanceof Variable) {
3622+
$scope = $this->lookForUnsetAllowedUndefinedExpressions($scope, $arg->value);
3623+
}
3624+
}
36363625
$hasYield = $hasYield || $result->hasYield();
36373626
$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
36383627
if ($i !== 0 || $closureBindScope === null) {
@@ -3646,6 +3635,41 @@ private function processArgs(
36463635
$scope = $scope->popInFunctionCall();
36473636
}
36483637

3638+
foreach ($args as $i => $arg) {
3639+
if (!isset($parameters) || $parametersAcceptor === null) {
3640+
continue;
3641+
}
3642+
3643+
$byRefType = new MixedType();
3644+
$assignByReference = false;
3645+
if (isset($parameters[$i])) {
3646+
$assignByReference = $parameters[$i]->passedByReference()->createsNewVariable();
3647+
if (isset($paramOutTypes[$parameters[$i]->getName()])) {
3648+
$byRefType = $paramOutTypes[$parameters[$i]->getName()];
3649+
}
3650+
} elseif (count($parameters) > 0 && $parametersAcceptor->isVariadic()) {
3651+
$lastParameter = $parameters[count($parameters) - 1];
3652+
$assignByReference = $lastParameter->passedByReference()->createsNewVariable();
3653+
if (isset($paramOutTypes[$lastParameter->getName()])) {
3654+
$byRefType = $paramOutTypes[$lastParameter->getName()];
3655+
}
3656+
}
3657+
3658+
if ($assignByReference) {
3659+
$argValue = $arg->value;
3660+
if ($argValue instanceof Variable && is_string($argValue->name)) {
3661+
$scope = $scope->assignVariable($argValue->name, $byRefType, new MixedType());
3662+
} else {
3663+
$scope = $scope->invalidateExpression($argValue);
3664+
}
3665+
} elseif ($calleeReflection !== null && $calleeReflection->hasSideEffects()->yes()) {
3666+
$argType = $scope->getType($arg->value);
3667+
if (!$argType->isObject()->no() || !(new ResourceType())->isSuperTypeOf($argType)->no()) {
3668+
$scope = $scope->invalidateExpression($arg->value, true);
3669+
}
3670+
}
3671+
}
3672+
36493673
return new ExpressionResult($scope, $hasYield, $throwPoints);
36503674
}
36513675

tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public function testDefinedVariables(): void
6666
'Undefined variable: $parseStrParameter',
6767
34,
6868
],
69+
[
70+
'Undefined variable: $parseStrParameter',
71+
36,
72+
],
6973
[
7074
'Undefined variable: $foo',
7175
39,

0 commit comments

Comments
 (0)