/**
* @param \PhpParser\Node[] $nodes
* @param \PHPStan\Analyser\Scope $scope
* @param \Closure $nodeCallback
* @param \PHPStan\Analyser\Scope $closureBindScope
*/
public function processNodes(array $nodes, Scope $scope, \Closure $nodeCallback, Scope $closureBindScope = null)
{
foreach ($nodes as $i => $node) {
if (!$node instanceof \PhpParser\Node) {
continue;
}
if ($scope->getInFunctionCall() !== null && $node instanceof Arg) {
$functionCall = $scope->getInFunctionCall();
$value = $node->value;
$parametersAcceptor = $this->findParametersAcceptorInFunctionCall($functionCall, $scope);
if ($parametersAcceptor !== null) {
$parameters = $parametersAcceptor->getParameters();
$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 && $value instanceof Variable) {
$scope = $scope->assignVariable($value->name, new MixedType(true));
}
}
}
$nodeScope = $scope;
if ($i === 0 && $closureBindScope !== null) {
$nodeScope = $closureBindScope;
}
$this->processNode($node, $nodeScope, $nodeCallback);
$scope = $this->lookForAssigns($scope, $node);
if ($node instanceof If_) {
if ($this->hasEarlyTermination($node->stmts, $scope)) {
$scope = $this->lookForTypeSpecificationsInEarlyTermination($scope, $node->cond);
$this->processNode($node->cond, $scope, function (Node $node, Scope $inScope) use(&$scope) {
if ($inScope->isNegated()) {
if ($node instanceof Isset_) {
foreach ($node->vars as $var) {
if ($var instanceof PropertyFetch) {
$scope = $scope->specifyFetchedPropertyFromIsset($var);
}
}
}
}
});
}
} elseif ($node instanceof Node\Stmt\Declare_) {
foreach ($node->declares as $declare) {
if ($declare instanceof Node\Stmt\DeclareDeclare && $declare->key === 'strict_types' && $declare->value instanceof Node\Scalar\LNumber && $declare->value->value === 1) {
$scope = $scope->enterDeclareStrictTypes();
break;
}
}
} elseif ($node instanceof FuncCall && $node->name instanceof Name && (string) $node->name === 'assert' && isset($node->args[0])) {
$scope = $this->lookForTypeSpecifications($scope, $node->args[0]->value);
} elseif ($node instanceof Assign && $node->var instanceof Array_) {
$scope = $this->lookForArrayDestructuringArray($scope, $node->var);
}
}
}