function enterNode(Node $node)
 {
     $class = get_class($node);
     if ($node instanceof Trait_) {
         return NodeTraverserInterface::DONT_TRAVERSE_CHILDREN;
     }
     if ($node instanceof Class_ || $node instanceof Trait_) {
         array_push($this->classStack, $node);
     }
     if ($node instanceof Node\FunctionLike) {
         // Typecast
         $this->pushFunctionScope($node);
     }
     if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignRef) {
         $this->handleAssignment($node);
     }
     if ($node instanceof Node\Stmt\StaticVar) {
         $this->setScopeExpression($node->name, $node->default);
     }
     if ($node instanceof Node\Stmt\Catch_) {
         $this->setScopeType(strval($node->var), strval($node->type));
     }
     if ($node instanceof Node\Stmt\Global_) {
         foreach ($node->vars as $var) {
             if ($var instanceof Node\Expr\Variable && gettype($var->name) == "string") {
                 $this->setScopeType(strval($var->name), Scope::MIXED_TYPE);
             }
         }
     }
     if ($node instanceof Node\Expr\MethodCall) {
         if (gettype($node->name) == "string") {
             $type = $this->typeInferrer->inferType(end($this->classStack) ?: null, $node->var, end($this->scopeStack));
             if ($type && $type[0] != "!") {
                 $method = $this->index->getAbstractedMethod($type, $node->name);
                 if ($method) {
                     /** @var FunctionLikeParameter[] $params */
                     $params = $method->getParameters();
                     $paramCount = count($params);
                     foreach ($node->args as $index => $arg) {
                         if (isset($params[$index]) && $params[$index]->isReference() || $index >= $paramCount && $paramCount > 0 && $params[$paramCount - 1]->isReference()) {
                             if ($arg->value instanceof Node\Expr\Variable && gettype($arg->value->name) == "string") {
                                 $this->setScopeType($arg->value->name, Scope::MIXED_TYPE);
                             }
                         }
                     }
                 }
             }
         }
     }
     if ($node instanceof Node\Expr\StaticCall) {
         if ($node->class instanceof Node\Name && gettype($node->name) == "string") {
             $method = $this->index->getAbstractedMethod(strval($node->class), strval($node->name));
             if ($method) {
                 /** @var FunctionLikeParameter[] $params */
                 $params = $method->getParameters();
                 $paramCount = count($params);
                 foreach ($node->args as $index => $arg) {
                     if (isset($params[$index]) && $params[$index]->isReference() || $index >= $paramCount && $paramCount > 0 && $params[$paramCount - 1]->isReference()) {
                         if ($arg->value instanceof Node\Expr\Variable && gettype($arg->value->name) == "string") {
                             $this->setScopeType($arg->value->name, Scope::MIXED_TYPE);
                         }
                     }
                 }
             }
         }
     }
     if ($node instanceof Node\Expr\FuncCall) {
         if ($node->name instanceof Node\Name) {
             $function = $this->index->getAbstractedFunction(strval($node->name));
             if ($function) {
                 $params = $function->getParameters();
                 $paramCount = count($params);
                 foreach ($node->args as $index => $arg) {
                     if ($arg->value instanceof Node\Expr\Variable && gettype($arg->value->name) == "string" && (isset($params[$index]) && $params[$index]->isReference() || $index >= $paramCount && $paramCount > 0 && $params[$paramCount - 1]->isReference())) {
                         $this->setScopeType($arg->value->name, Scope::MIXED_TYPE);
                     }
                 }
             }
         }
     }
     if ($node instanceof Node\Stmt\Foreach_) {
         if ($node->keyVar instanceof Node\Expr\Variable && gettype($node->keyVar->name) == "string") {
             $this->setScopeType(strval($node->keyVar->name), Scope::MIXED_TYPE);
         }
         if ($node->valueVar instanceof Node\Expr\Variable && gettype($node->valueVar->name) == "string") {
             $type = $this->typeInferrer->inferType(end($this->classStack) ?: null, $node->expr, end($this->scopeStack));
             if (substr($type, -2) == "[]") {
                 $type = substr($type, 0, -2);
             } else {
                 $type = Scope::MIXED_TYPE;
             }
             $this->setScopeType(strval($node->valueVar->name), $type);
         } else {
             if ($node->valueVar instanceof Node\Expr\List_) {
                 foreach ($node->valueVar->vars as $var) {
                     if ($var instanceof Node\Expr\Variable && gettype($var->name) == "string") {
                         $this->setScopeType(strval($var->name), Scope::MIXED_TYPE);
                     }
                 }
             }
         }
     }
     if ($node instanceof Node\Stmt\If_ || $node instanceof Node\Stmt\ElseIf_) {
         if ($node instanceof Node\Stmt\ElseIf_) {
             // Pop the previous if's scope
             array_pop($this->scopeStack);
         }
         $this->pushIfScope($node);
     }
     if ($node instanceof Node\Stmt\Else_) {
         // The previous scope was only valid for the if side.
         array_pop($this->scopeStack);
     }
     if (isset($this->checks[$class])) {
         foreach ($this->checks[$class] as $check) {
             $check->run($this->file, $node, end($this->classStack) ?: null, end($this->scopeStack) ?: null);
         }
     }
     return null;
 }
 /**
  * Do some simplistic checks to see if we can figure out object type.  If we can, then we can check method calls
  * using that variable for correctness.
  * @param Node\Expr $expr
  * @param Scope     $scope
  * @return string
  */
 function inferType(Node\Stmt\ClassLike $inside = null, Node\Expr $expr = null, Scope $scope)
 {
     if ($expr instanceof Node\Expr\AssignOp) {
         return $this->inferType($inside, $expr->expr, $scope);
     } else {
         if ($expr instanceof Node\Scalar) {
             return Scope::SCALAR_TYPE;
         } else {
             if ($expr instanceof Node\Expr\New_ && $expr->class instanceof Node\Name) {
                 $className = strval($expr->class);
                 if (strcasecmp($className, "self") == 0) {
                     $className = $inside ? strval($inside->namespacedName) : Scope::MIXED_TYPE;
                 } else {
                     if (strcasecmp($className, "static") == 0) {
                         $className = Scope::MIXED_TYPE;
                     }
                 }
                 return $className;
             } else {
                 if ($expr instanceof Node\Expr\Variable && gettype($expr->name) == "string") {
                     $varName = strval($expr->name);
                     if ($varName == "this" && $inside) {
                         return strval($inside->namespacedName);
                     }
                     $scopeType = $scope->getVarType($varName);
                     if ($scopeType != Scope::UNDEFINED) {
                         return $scopeType;
                     }
                 } else {
                     if ($expr instanceof Node\Expr\Closure) {
                         return "callable";
                     } else {
                         if ($expr instanceof Node\Expr\FuncCall && $expr->name instanceof Node\Name) {
                             $func = $this->index->getFunction($expr->name);
                             /*
                             			if($func) {
                             				$namespacedReturn =$func->getAttribute("namespacedReturn");
                             				return $namespacedReturn ?: Scope::MIXED_TYPE;
                             			}*/
                         } else {
                             if ($expr instanceof Node\Expr\MethodCall && gettype($expr->name) == "string") {
                                 $class = $this->inferType($inside, $expr->var, $scope);
                                 if (!empty($class) && $class[0] != "!") {
                                     $method = $this->index->getAbstractedMethod($class, strval($expr->name));
                                     if ($method) {
                                         $type = $method->getReturnType();
                                         if ($type) {
                                             return $type;
                                         }
                                         /*
                                         $type = $method->getDocBlockReturnType();
                                         if($type) {
                                         	return $type;
                                         }
                                         */
                                     }
                                 }
                             } else {
                                 if ($expr instanceof Node\Expr\PropertyFetch) {
                                     return $this->inferPropertyFetch($expr, $inside, $scope);
                                 } else {
                                     if ($expr instanceof Node\Expr\ArrayDimFetch) {
                                         $type = $this->inferType($inside, $expr->var, $scope);
                                         if (substr($type, -2) == "[]") {
                                             return substr($type, 0, -2);
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return Scope::MIXED_TYPE;
 }