Skip to content

Commit

Permalink
Do not influence types of arguments before the function is called
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Oct 5, 2023
1 parent 0b8dca7 commit c45d42d
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 24 deletions.
72 changes: 48 additions & 24 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3580,43 +3580,27 @@ private function processArgs(
$hasYield = false;
$throwPoints = [];
foreach ($args as $i => $arg) {
$originalArg = $arg->getAttribute(ArgumentsNormalizer::ORIGINAL_ARG_ATTRIBUTE) ?? $arg;
$nodeCallback($originalArg, $scope);
$assignByReference = false;
if (isset($parameters) && $parametersAcceptor !== null) {
$byRefType = new MixedType();
$assignByReference = false;
if (isset($parameters[$i])) {
$assignByReference = $parameters[$i]->passedByReference()->createsNewVariable();
$parameterType = $parameters[$i]->getType();

if (isset($paramOutTypes[$parameters[$i]->getName()])) {
$byRefType = $paramOutTypes[$parameters[$i]->getName()];
}
} elseif (count($parameters) > 0 && $parametersAcceptor->isVariadic()) {
$lastParameter = $parameters[count($parameters) - 1];
$assignByReference = $lastParameter->passedByReference()->createsNewVariable();
$parameterType = $lastParameter->getType();

if (isset($paramOutTypes[$lastParameter->getName()])) {
$byRefType = $paramOutTypes[$lastParameter->getName()];
}
}
}

if ($assignByReference) {
$argValue = $arg->value;
if ($argValue instanceof Variable && is_string($argValue->name)) {
$scope = $scope->assignVariable($argValue->name, $byRefType, new MixedType());
} else {
$scope = $scope->invalidateExpression($argValue);
}
} elseif ($calleeReflection !== null && $calleeReflection->hasSideEffects()->yes()) {
$argType = $scope->getType($arg->value);
if (!$argType->isObject()->no() || !(new ResourceType())->isSuperTypeOf($argType)->no()) {
$scope = $scope->invalidateExpression($arg->value, true);
}
if ($assignByReference) {
if ($arg->value instanceof Variable) {
$scope = $this->lookForSetAllowedUndefinedExpressions($scope, $arg->value);
}
}

$originalArg = $arg->getAttribute(ArgumentsNormalizer::ORIGINAL_ARG_ATTRIBUTE) ?? $arg;
$nodeCallback($originalArg, $scope);

$originalScope = $scope;
$scopeToPass = $scope;
if ($i === 0 && $closureBindScope !== null) {
Expand All @@ -3633,6 +3617,11 @@ private function processArgs(
$result = $this->processExprNode($arg->value, $scopeToPass, $nodeCallback, $context->enterDeep());
}
$scope = $result->getScope();
if ($assignByReference) {
if ($arg->value instanceof Variable) {
$scope = $this->lookForUnsetAllowedUndefinedExpressions($scope, $arg->value);
}
}
$hasYield = $hasYield || $result->hasYield();
$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
if ($i !== 0 || $closureBindScope === null) {
Expand All @@ -3646,6 +3635,41 @@ private function processArgs(
$scope = $scope->popInFunctionCall();
}

foreach ($args as $i => $arg) {
if (!isset($parameters) || $parametersAcceptor === null) {
continue;
}

$byRefType = new MixedType();
$assignByReference = false;
if (isset($parameters[$i])) {
$assignByReference = $parameters[$i]->passedByReference()->createsNewVariable();
if (isset($paramOutTypes[$parameters[$i]->getName()])) {
$byRefType = $paramOutTypes[$parameters[$i]->getName()];
}
} elseif (count($parameters) > 0 && $parametersAcceptor->isVariadic()) {
$lastParameter = $parameters[count($parameters) - 1];
$assignByReference = $lastParameter->passedByReference()->createsNewVariable();
if (isset($paramOutTypes[$lastParameter->getName()])) {
$byRefType = $paramOutTypes[$lastParameter->getName()];
}
}

if ($assignByReference) {
$argValue = $arg->value;
if ($argValue instanceof Variable && is_string($argValue->name)) {
$scope = $scope->assignVariable($argValue->name, $byRefType, new MixedType());
} else {
$scope = $scope->invalidateExpression($argValue);
}
} elseif ($calleeReflection !== null && $calleeReflection->hasSideEffects()->yes()) {
$argType = $scope->getType($arg->value);
if (!$argType->isObject()->no() || !(new ResourceType())->isSuperTypeOf($argType)->no()) {
$scope = $scope->invalidateExpression($arg->value, true);
}
}
}

return new ExpressionResult($scope, $hasYield, $throwPoints);
}

Expand Down
4 changes: 4 additions & 0 deletions tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ public function testDefinedVariables(): void
'Undefined variable: $parseStrParameter',
34,
],
[
'Undefined variable: $parseStrParameter',
36,
],
[
'Undefined variable: $foo',
39,
Expand Down

0 comments on commit c45d42d

Please sign in to comment.