private function traverseCall(\PHPParser_Node $node, LinkedFlowScope $scope)
 {
     assert($node instanceof \PHPParser_Node_Expr_MethodCall || $node instanceof \PHPParser_Node_Expr_FuncCall || $node instanceof \PHPParser_Node_Expr_StaticCall);
     $scope = $this->traverseChildren($node, $scope);
     // Propagate type for constants
     if (NodeUtil::isConstantDefinition($node)) {
         $constantName = $node->args[0]->value->value;
         if ($constant = $this->typeRegistry->getConstant($constantName)) {
             $constant->setPhpType($this->getType($node->args[1]->value));
         }
     }
     // If the assert function is called inside a block node, we are just going to assume
     // that some sort of exception is thrown if the assert fails (and it will not silently
     // be ignored).
     // TODO: This needs to be extracted as a general concept where we can have different
     //       effects for functions/methods. For example, array_pop affects the known item
     //       types of arrays on which it is called.
     if ($node->getAttribute('parent') instanceof BlockNode && NodeUtil::isMaybeFunctionCall($node, 'assert') && isset($node->args[0])) {
         $scope = $this->reverseInterpreter->getPreciserScopeKnowingConditionOutcome($node->args[0]->value, $scope, true);
     }
     $returnType = null;
     if (null !== ($function = $this->typeRegistry->getCalledFunctionByNode($node))) {
         $node->setAttribute('returns_by_ref', $function->isReturnByRef());
         $argValues = $argTypes = array();
         foreach ($node->args as $arg) {
             $argValues[] = $arg->value;
             $argTypes[] = $this->getType($arg);
         }
         if ($function instanceof ContainerMethodInterface) {
             $objType = $function->getContainer();
             $maybeReturnType = $function->getReturnType();
             if (null !== ($restrictedType = $this->methodInterpreter->getPreciserMethodReturnTypeKnowingArguments($function, $argValues, $argTypes))) {
                 $maybeReturnType = $restrictedType;
             }
             $returnType = $this->updateThisReference($node instanceof \PHPParser_Node_Expr_MethodCall ? $node->var : $node->class, $scope->getTypeOfThis(), $objType, $maybeReturnType);
         } else {
             if ($function instanceof GlobalFunction) {
                 if (null !== ($restrictedType = $this->functionInterpreter->getPreciserFunctionReturnTypeKnowingArguments($function, $argValues, $argTypes))) {
                     $returnType = $restrictedType;
                 } else {
                     if (null === $returnType) {
                         $returnType = $function->getReturnType();
                     }
                 }
             } else {
                 throw new \LogicException(sprintf('Unknown function "%s".', get_class($function)));
             }
         }
     }
     $node->setAttribute('type', $returnType ?: $this->typeRegistry->getNativeType('unknown'));
     return $scope;
 }
 private function enterNode(\PHPParser_Node $node)
 {
     if (NodeUtil::isMethodContainer($node)) {
         $this->commentParser->setCurrentClassName(implode("\\", $node->namespacedName->parts));
         $this->commentParser->setImportedNamespaces($this->importedNamespaces);
         $this->classParser->setImportedNamespaces($this->importedNamespaces);
         $class = $this->classParser->parse($node);
         $this->classFiles[$class] = $this->phpFile;
         if ($this->typeRegistry->hasClass($class->getName(), TypeRegistry::LOOKUP_NO_CACHE)) {
             $this->analyzer->logger->warning(sprintf('The class "%s" has been defined more than once (maybe as a fixture for code generation). Ignoring the second definition.', $class->getName()));
             return;
         }
         $this->typeRegistry->registerClass($class);
     } else {
         if ($node instanceof \PHPParser_Node_Stmt_Function) {
             $this->functionParser->setImportedNamespaces($this->importedNamespaces);
             $function = $this->functionParser->parse($node);
             if ($this->typeRegistry->hasFunction($functionName = $function->getName(), false)) {
                 $this->analyzer->logger->warning(sprintf('The function "%s" has been defined more than once (probably conditionally). Ignoring the second definition.', $functionName));
                 return;
             }
             $this->typeRegistry->registerFunction($function);
         } else {
             if (NodeUtil::isConstantDefinition($node)) {
                 assert($node instanceof \PHPParser_Node_Expr_FuncCall);
                 if (!$node->args[0]->value instanceof \PHPParser_Node_Scalar_String) {
                     return;
                 }
                 $constant = new GlobalConstant($node->args[0]->value->value);
                 $constant->setAstNode($node);
                 $constant->setPhpType($this->typeRegistry->getNativeType('unknown'));
                 if (null !== ($type = $node->args[1]->value->getAttribute('type'))) {
                     $constant->setPhpType($type);
                 }
                 if ($this->typeRegistry->hasConstant($constant->getName(), false)) {
                     $this->analyzer->logger->warning(sprintf('The constant "%s" was defined more than once. Ignoring all but first definition.', $constant->getName()));
                     return;
                 }
                 $this->typeRegistry->registerConstant($constant);
             }
         }
     }
 }