private function lookForAssigns(Scope $scope, \PhpParser\Node $node) : Scope
{
if ($node instanceof StaticVar) {
$scope = $scope->assignVariable($node->name, $node->default !== null ? $scope->getType($node->default) : null);
} elseif ($node instanceof Static_) {
foreach ($node->vars as $var) {
$scope = $this->lookForAssigns($scope, $var);
}
} elseif ($node instanceof If_) {
$scope = $this->lookForAssigns($scope, $node->cond);
$statements = [new StatementList($scope, array_merge([$node->cond], $node->stmts)), new StatementList($scope, $node->else !== null ? $node->else->stmts : ($this->defineVariablesWithoutDefaultBranch ? null : []))];
foreach ($node->elseifs as $elseIf) {
$statements[] = new StatementList($scope, array_merge([$elseIf->cond], $elseIf->stmts));
}
$scope = $this->lookForAssignsInBranches($scope, $statements);
} elseif ($node instanceof TryCatch) {
if (property_exists($node, 'finally') && (isset($node->finally) || $node->finally === null)) {
$finallyStatements = $node->finally !== null ? $node->finally->stmts : null;
} elseif (property_exists($node, 'finallyStmts') && (isset($node->finallyStmts) || $node->finallyStmts === null)) {
$finallyStatements = $node->finallyStmts;
} else {
throw new \PHPStan\ShouldNotHappenException();
}
$statements = [new StatementList($scope, $node->stmts), new StatementList($scope, $finallyStatements)];
foreach ($node->catches as $catch) {
if (isset($catch->types)) {
$catchTypes = $catch->types;
} elseif (isset($catch->type)) {
$catchTypes = [$catch->type];
} else {
throw new \PHPStan\ShouldNotHappenException();
}
$statements[] = new StatementList($scope->enterCatch($catchTypes, $catch->var), $catch->stmts);
}
$scope = $this->lookForAssignsInBranches($scope, $statements);
} elseif ($node instanceof MethodCall || $node instanceof FuncCall || $node instanceof Expr\StaticCall) {
if ($node instanceof MethodCall) {
$scope = $this->lookForAssigns($scope, $node->var);
}
foreach ($node->args as $argument) {
$scope = $this->lookForAssigns($scope, $argument);
}
$parametersAcceptor = $this->findParametersAcceptorInFunctionCall($node, $scope);
if ($parametersAcceptor !== null) {
$parameters = $parametersAcceptor->getParameters();
foreach ($node->args as $i => $arg) {
$assignByReference = false;
if (isset($parameters[$i])) {
$assignByReference = $parameters[$i]->isPassedByReference();
} elseif (count($parameters) > 0 && $parametersAcceptor->isVariadic()) {
$lastParameter = $parameters[count($parameters) - 1];
$assignByReference = $lastParameter->isPassedByReference();
}
if (!$assignByReference) {
continue;
}
$arg = $node->args[$i]->value;
if ($arg instanceof Variable && is_string($arg->name)) {
$scope = $scope->assignVariable($arg->name, new MixedType(true));
}
}
}
} elseif ($node instanceof BinaryOp) {
$scope = $this->lookForAssigns($scope, $node->left);
$scope = $this->lookForAssigns($scope, $node->right);
} elseif ($node instanceof Arg) {
$scope = $this->lookForAssigns($scope, $node->value);
} elseif ($node instanceof BooleanNot) {
$scope = $this->lookForAssigns($scope, $node->expr);
} elseif ($node instanceof Ternary) {
$scope = $this->lookForAssigns($scope, $node->else);
} elseif ($node instanceof List_) {
if (isset($node->items)) {
$nodeItems = $node->items;
} elseif (isset($node->vars)) {
$nodeItems = $node->vars;
} else {
throw new \PHPStan\ShouldNotHappenException();
}
foreach ($nodeItems as $item) {
if ($item === null) {
continue;
}
$itemValue = $item;
if ($itemValue instanceof ArrayItem) {
$itemValue = $itemValue->value;
}
if ($itemValue instanceof Variable) {
$scope = $scope->assignVariable($itemValue->name);
} elseif ($itemValue instanceof ArrayDimFetch && $itemValue->var instanceof Variable) {
$scope = $scope->assignVariable($itemValue->var->name);
} else {
$scope = $this->lookForAssigns($scope, $itemValue);
}
}
} elseif ($node instanceof Array_) {
foreach ($node->items as $item) {
$scope = $this->lookForAssigns($scope, $item->value);
}
} elseif ($node instanceof New_) {
foreach ($node->args as $arg) {
$scope = $this->lookForAssigns($scope, $arg);
}
} elseif ($node instanceof Do_) {
foreach ($node->stmts as $statement) {
$scope = $this->lookForAssigns($scope, $statement);
}
} elseif ($node instanceof Switch_) {
$statements = [];
$hasDefault = false;
foreach ($node->cases as $case) {
if ($case->cond === null) {
$hasDefault = true;
}
$statements[] = new StatementList($scope, $case->stmts);
}
if (!$hasDefault) {
$statements = [];
}
$scope = $this->lookForAssignsInBranches($scope, $statements, true);
} elseif ($node instanceof Cast) {
$scope = $this->lookForAssigns($scope, $node->expr);
} elseif ($this->polluteScopeWithLoopInitialAssignments) {
if ($node instanceof For_) {
foreach ($node->init as $initExpr) {
$scope = $this->lookForAssigns($scope, $initExpr);
}
foreach ($node->cond as $condExpr) {
$scope = $this->lookForAssigns($scope, $condExpr);
}
} elseif ($node instanceof While_) {
$scope = $this->lookForAssigns($scope, $node->cond);
}
} elseif ($node instanceof ErrorSuppress) {
$scope = $this->lookForAssigns($scope, $node->expr);
} elseif ($node instanceof \PhpParser\Node\Stmt\Unset_) {
foreach ($node->vars as $var) {
if ($var instanceof Variable && is_string($var->name)) {
$scope = $scope->unsetVariable($var->name);
}
}
} elseif ($node instanceof Echo_) {
foreach ($node->exprs as $echoedExpr) {
$scope = $this->lookForAssigns($scope, $echoedExpr);
}
} elseif ($node instanceof Print_) {
$scope = $this->lookForAssigns($scope, $node->expr);
} elseif ($node instanceof Foreach_) {
$scope = $this->lookForAssigns($scope, $node->expr);
} elseif ($node instanceof Isset_) {
foreach ($node->vars as $var) {
$scope = $this->lookForAssigns($scope, $var);
}
} elseif ($node instanceof ArrayDimFetch && $node->dim !== null) {
$scope = $this->lookForAssigns($scope, $node->dim);
}
$scope = $this->updateScopeForVariableAssign($scope, $node);
return $scope;
}