/**
  * @param $fileName
  * @param \PhpParser\Node\Expr\New_ $node
  */
 function run($fileName, $node, ClassLike $inside = null, Scope $scope = null)
 {
     if ($node->class instanceof Name) {
         $name = $node->class->toString();
         if (strcasecmp($name, "self") != 0 && strcasecmp($name, "static") != 0 && !$this->symbolTable->ignoreType($name)) {
             $this->incTests();
             $class = $this->symbolTable->getAbstractedClass($name);
             if (!$class) {
                 $this->emitError($fileName, $node, self::TYPE_UNKNOWN_CLASS, "Attempt to instantiate unknown class {$name}");
                 return;
             }
             if ($class->isDeclaredAbstract()) {
                 $this->emitError($fileName, $node, self::TYPE_SIGNATURE_TYPE, "Attempt to instantiate abstract class {$name}");
                 return;
             }
             $method = Util::findAbstractedMethod($name, "__construct", $this->symbolTable);
             if (!$method) {
                 $minParams = $maxParams = 0;
             } else {
                 if ($method->getAccessLevel() == "private" && (!$inside || strcasecmp($inside->namespacedName, $name) != 0)) {
                     $this->emitError($fileName, $node, self::TYPE_SCOPE_ERROR, "Attempt to call private constructor outside of class {$name}");
                     return;
                 }
                 $maxParams = count($method->getParameters());
                 $minParams = $method->getMinimumRequiredParameters();
                 if (strcasecmp("imagick", $name) == 0) {
                     $minParams = 0;
                     $maxParams = 1;
                 }
             }
             $passedArgCount = count($node->args);
             if ($passedArgCount < $minParams) {
                 $this->emitError($fileName, $node, self::TYPE_SIGNATURE_COUNT, "Call to {$name}::__construct passing {$passedArgCount} count, required count={$minParams}");
             }
             if ($passedArgCount > $maxParams) {
                 //$this->emitError($fileName, $node, "Parameter mismatch","Call to $name::__construct passing too many parameters ($passedArgCount instead of $maxParams)");
             }
         }
     }
 }
Ejemplo n.º 2
0
 /**
  * @param                                    $fileName
  * @param \PhpParser\Node\Expr\MethodCall $node
  */
 function run($fileName, $node, ClassLike $inside = null, Scope $scope = null)
 {
     if ($inside instanceof Trait_) {
         // Traits should be converted into methods in the class, so that we can check them in context.
         return;
     }
     if ($node->name instanceof Expr) {
         // Variable method name.  Yuck!
         return;
     }
     $methodName = strval($node->name);
     $varName = "{expr}";
     $className = "";
     if ($node->var instanceof Variable && $node->var->name == "this" && !$inside) {
         $this->emitError($fileName, $node, self::TYPE_SCOPE_ERROR, "Can't use \$this outside of a class");
         return;
     }
     if ($scope) {
         $className = $this->inferenceEngine->inferType($inside, $node->var, $scope);
     }
     if ($className != "" && $className[0] != "!") {
         if (!$this->symbolTable->getAbstractedClass($className)) {
             $this->emitError($fileName, $node, self::TYPE_UNKNOWN_CLASS, "Unknown class {$className} in method call to {$methodName}()");
             return;
         }
         //echo $fileName." ".$node->getLine(). " : Looking up $className->$methodName\n";
         $method = Util::findAbstractedSignature($className, $methodName, $this->symbolTable);
         if ($method) {
             $this->checkMethod($fileName, $node, $className, $scope, $method);
         } else {
             // If there is a magic __call method, then we can't know if it will handle these calls.
             if (!Util::findAbstractedMethod($className, "__call", $this->symbolTable) && !$this->symbolTable->isParentClassOrInterface("iteratoriterator", $className)) {
                 $this->emitError($fileName, $node, self::TYPE_UNKNOWN_METHOD, "Call to unknown method of {$className}: \$" . $varName . "->" . $methodName);
             }
         }
     }
 }
Ejemplo n.º 3
0
 /**
  * @param $fileName
  * @param \PhpParser\Node\Stmt\Class_ $node
  */
 function run($fileName, $node, ClassLike $inside = null, Scope $scope = null)
 {
     if ($node->implements) {
         $arr = is_array($node->implements) ? $node->implements : [$node->implements];
         foreach ($arr as $interface) {
             $name = $interface->toString();
             $this->incTests();
             if ($name) {
                 $interface = $this->symbolTable->getAbstractedClass($name);
                 if (!$interface) {
                     $this->emitError($fileName, $node, self::TYPE_UNKNOWN_CLASS, $node->name . " implements unknown interface " . $name);
                 } else {
                     // Don't force abstract classes to implement all methods.
                     if (!$node->isAbstract()) {
                         foreach ($interface->getMethodNames() as $interfaceMethod) {
                             $classMethod = $this->implementsMethod($fileName, $node, $interfaceMethod);
                             if (!$classMethod) {
                                 if (!$node->isAbstract()) {
                                     $this->emitError($fileName, $node, self::TYPE_UNIMPLEMENTED_METHOD, $node->name . " does not implement method " . $interfaceMethod);
                                 }
                             } else {
                                 $this->checkMethod($node, $classMethod, $interface, $interface->getMethod($interfaceMethod));
                             }
                         }
                     }
                 }
             }
         }
     }
     if ($node->extends) {
         $class = new \Guardrail\Abstractions\Class_($node);
         $parentClass = $this->symbolTable->getAbstractedClass($node->extends);
         if (!$parentClass) {
             $this->emitError($fileName, $node->extends, self::TYPE_UNKNOWN_CLASS, "Unable to find parent " . $node->extends);
         }
         foreach ($class->getMethodNames() as $methodName) {
             if ($methodName != "__construct") {
                 $method = Util::findAbstractedMethod($node->extends, $methodName, $this->symbolTable);
                 if ($method) {
                     $this->checkMethod($node, $class->getMethod($methodName), $parentClass, $method);
                 }
             }
         }
     }
 }
Ejemplo n.º 4
0
 function getAbstractedMethod($className, $methodName)
 {
     $cacheName = strtolower($className . "::" . $methodName);
     $ob = $this->cache->get("AClassMethod:" . $cacheName);
     if (!$ob) {
         $ob = \Guardrail\Util::findAbstractedMethod($className, $methodName, $this);
         if (!$ob && strpos($className, "\\") === false) {
             try {
                 $refl = new \ReflectionMethod($className, $methodName);
                 $ob = new \Guardrail\Abstractions\ReflectedClassMethod($refl);
             } catch (\ReflectionException $e) {
                 $ob = null;
             }
         }
         if ($ob) {
             $this->cache->add("AClassMethod:" . $cacheName, $ob);
         }
     }
     return $ob;
 }
 function getConstructorDependencies($className)
 {
     $method = Util::findAbstractedMethod($className, "__construct", $this->symbolTable);
     $dependencies = [];
     if ($method) {
         foreach ($method->getParameters() as $param) {
             $dependencies[] = strval($param->getType());
         }
     }
     return $dependencies;
 }
Ejemplo n.º 6
0
 /**
  * @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)");
                 }
             }
         }
     }
 }