/**
  * @param string $fileName
  * @param \PhpParser\Node\Expr\Variable $node
  */
 function run($fileName, $node, ClassLike $inside = null, Scope $scope = null)
 {
     if (gettype($node->name) == 'string' && $scope && !$scope->isGlobal()) {
         $name = $name = $node->name;
         if ($name != "GLOBALS" && $name != "_GET" && $name != "_POST" && $name != "_COOKIE" && $name != "_REQUEST" && $name != "this" && $name != "_SERVER" && $name != "_SESSION" && $name != "_FILES" && $name != "http_response_header") {
             $this->incTests();
             if ($scope->getVarType($name) == Scope::UNDEFINED) {
                 $this->emitError($fileName, $node, self::TYPE_UNKNOWN_VARIABLE, "Undefined variable: {$name}");
             }
         }
     }
 }
예제 #2
0
 /**
  * @param           $fileName
  * @param           $node
  * @param string    $inside
  * @param Scope     $scope
  * @param           $method
  */
 protected function checkMethod($fileName, $node, $inside, Scope $scope, MethodInterface $method)
 {
     if ($method->isStatic()) {
         $this->emitError($fileName, $node, self::TYPE_INCORRECT_DYNAMIC_CALL, "Call to static method of {$inside}::" . $method->getName() . " non-statically");
         return;
     }
     $params = $method->getParameters();
     $minimumArgs = $method->getMinimumRequiredParameters();
     if (count($node->args) < $minimumArgs) {
         $this->emitError($fileName, $node, self::TYPE_SIGNATURE_COUNT, "Function call parameter count mismatch to method " . $method->getName() . " (passed " . count($node->args) . " requires {$minimumArgs})");
     }
     if (count($node->args) > count($params) && !$method->isVariadic()) {
         $this->emitError($fileName, $node, self::TYPE_SIGNATURE_COUNT_EXCESS, "Too many parameters to non-variadic method " . $method->getName() . " (passed " . count($node->args) . " only takes " . count($params) . ")");
     }
     foreach ($node->args as $index => $arg) {
         if ($scope && $arg->value instanceof \PhpParser\Node\Expr\Variable && $index < count($params) && $params[$index]->getType() != "") {
             $variableName = $arg->value->name;
             $type = $scope->getVarType($variableName);
             $expectedType = $params[$index]->getType();
             if (!in_array($type, [Scope::SCALAR_TYPE, Scope::MIXED_TYPE, Scope::UNDEFINED]) && $type != "" && !$this->symbolTable->isParentClassOrInterface($expectedType, $type)) {
                 $this->emitError($fileName, $node, self::TYPE_SIGNATURE_TYPE, "Variable passed to method " . $inside . "->" . $node->name . "() parameter \${$variableName} must be a {$expectedType}, passing {$type}");
             }
         }
     }
 }
예제 #3
0
 function pushFunctionScope(Node\FunctionLike $func)
 {
     $isStatic = true;
     if ($func instanceof Node\Stmt\ClassMethod) {
         $isStatic = $func->isStatic();
     }
     $scope = new Scope($isStatic);
     foreach ($func->getParams() as $param) {
         $scope->setVarType(strval($param->name), strval($param->type));
     }
     if ($func instanceof Node\Expr\Closure) {
         $oldScope = end($this->scopeStack);
         foreach ($func->uses as $variable) {
             $type = $oldScope->getVarType($variable->var);
             if ($type == Scope::UNDEFINED) {
                 $type = Scope::MIXED_TYPE;
             }
             $scope->setVarType($variable->var, $type);
         }
     }
     array_push($this->scopeStack, $scope);
 }
 /**
  * @param $fileName
  * @param \PhpParser\Node\Expr\StaticCall $call
  */
 function run($fileName, $call, ClassLike $inside = null, Scope $scope = null)
 {
     if ($call->class instanceof Name && gettype($call->name) == "string") {
         $name = $call->class->toString();
         if ($this->symbolTable->ignoreType($name)) {
             return;
         }
         $originalName = $name;
         $possibleDynamic = false;
         switch (strtolower($name)) {
             case 'self':
                 $possibleDynamic = true;
                 // Fall through
             // Fall through
             case 'static':
                 if (!$inside) {
                     $this->emitError($fileName, $call, self::TYPE_SCOPE_ERROR, "Can't access using self:: outside of a class");
                     return;
                 }
                 $name = $inside->namespacedName;
                 break;
             case 'parent':
                 if (!$inside) {
                     $this->emitError($fileName, $call, self::TYPE_SCOPE_ERROR, "Can't access using parent:: outside of a class");
                     return;
                 }
                 $possibleDynamic = true;
                 if ($inside->extends) {
                     $name = strval($inside->extends);
                 } else {
                     $this->emitError($fileName, $call, self::TYPE_SCOPE_ERROR, "Can't access using parent:: in a class with no parent");
                     return;
                 }
                 break;
             default:
                 if ($inside) {
                     $currentClass = strval($inside->namespacedName);
                     if ($this->symbolTable->isParentClassOrInterface($name, $currentClass)) {
                         $possibleDynamic = true;
                     }
                 }
                 break;
         }
         $this->incTests();
         $class = $this->symbolTable->getAbstractedClass($name);
         if (!$class) {
             if (!$this->symbolTable->ignoreType($name)) {
                 $this->emitError($fileName, $call, self::TYPE_UNKNOWN_CLASS, "Static call to unknown class {$name}::" . $call->name);
             }
         } else {
             $method = Util::findAbstractedMethod($name, $call->name, $this->symbolTable);
             if ($call->name == "__construct" && !$method) {
                 // Find a PHP 4 style constructor (function name == class name)
                 $method = Util::findAbstractedMethod($name, $name, $this->symbolTable);
             }
             if (!$method) {
                 if (!Util::findAbstractedMethod($name, "__callStatic", $this->symbolTable) && (!$possibleDynamic || !Util::findAbstractedMethod($name, "__call", $this->symbolTable))) {
                     $this->emitError($fileName, $call, self::TYPE_UNKNOWN_METHOD, "Unable to find method.  {$name}::" . $call->name);
                 }
             } else {
                 if (!$method->isStatic()) {
                     if (!$scope->isStatic() && $possibleDynamic) {
                         if ($call->name != "__construct" && $call->class != "parent") {
                             // echo "Static call in $fileName " . $call->getLine() . "\n";
                         }
                     } else {
                         $this->emitError($fileName, $call, self::TYPE_INCORRECT_DYNAMIC_CALL, "Attempt to call non-static method: {$name}::" . $call->name . " statically");
                     }
                 }
                 $minimumParams = $method->getMinimumRequiredParameters();
                 if (count($call->args) < $minimumParams) {
                     $this->emitError($fileName, $call, self::TYPE_SIGNATURE_COUNT, "Static call to method {$name}::" . $call->name . " does not pass enough parameters (" . count($call->args) . " passed {$minimumParams} required)");
                 }
             }
         }
     }
 }