Пример #1
0
 /**
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitProp(Node $node) : Context
 {
     $property_name = $node->children['prop'];
     // Things like $foo->$bar
     if (!is_string($property_name)) {
         return $this->context;
     }
     assert(is_string($property_name), "Property must be string in context {$this->context}");
     try {
         $clazz = AST::classFromNodeInContext($node, $this->context, $this->code_base);
     } catch (CodeBaseException $exception) {
         Log::err(Log::EFATAL, $exception->getMessage(), $this->context->getFile(), $node->lineno);
     } catch (\Exception $exception) {
         // If we can't figure out what kind of a class
         // this is, don't worry about it
         return $this->context;
     }
     if (!$clazz->hasPropertyWithName($this->code_base, $property_name)) {
         // Check to see if the class has a __set method
         if (!$clazz->hasMethodWithName($this->code_base, '__set')) {
             if (Config::get()->allow_missing_properties) {
                 try {
                     // Create the property
                     AST::getOrCreatePropertyFromNodeInContext($property_name, $node, $this->context, $this->code_base);
                 } catch (\Exception $exception) {
                     // swallow it
                 }
             } else {
                 Log::err(Log::EAVAIL, "Missing property with name '{$property_name}'", $this->context->getFile(), $node->lineno);
             }
         }
         return $this->context;
     }
     try {
         $property = $clazz->getPropertyByNameInContext($this->code_base, $property_name, $this->context);
     } catch (AccessException $exception) {
         Log::err(Log::EACCESS, $exception->getMessage(), $this->context->getFile(), $node->lineno);
         return $this->context;
     }
     if (!$this->right_type->canCastToExpandedUnionType($property->getUnionType(), $this->code_base)) {
         Log::err(Log::ETYPE, "assigning {$this->right_type} to property but {$clazz->getFQSEN()}::{$property->getName()} is {$property->getUnionType()}", $this->context->getFile(), $node->lineno);
         return $this->context;
     }
     // After having checked it, add this type to it
     $property->getUnionType()->addUnionType($this->right_type);
     return $this->context;
 }
Пример #2
0
 /**
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitStaticCall(Node $node) : Context
 {
     // Get the name of the method being called
     $method_name = $node->children['method'];
     // Give up on things like Class::$var
     if (!is_string($method_name)) {
         return $this->context;
     }
     // Get the name of the static class being referenced
     $static_class = '';
     if ($node->children['class']->kind == \ast\AST_NAME) {
         $static_class = $node->children['class']->children['name'];
     }
     // Short circuit on a constructor being called statically
     // on something other than 'parent'
     if ($method_name === '__construct') {
         if ($static_class !== 'parent') {
             Log::err(Log::EUNDEF, "static call to undeclared method {$static_class}::{$method_name}()", $this->context->getFile(), $node->lineno);
         }
         return $this->context;
     }
     try {
         // Get a reference to the method being called
         $method = AST::classMethodFromNodeInContext($node, $this->context, $this->code_base, $method_name, true);
         // If the method isn't static and we're not calling
         // it on 'parent', we're in a bad spot.
         if (!$method->isStatic() && 'parent' !== $static_class) {
             $clazz = AST::classFromNodeInContext($node, $this->context, $this->code_base);
             Log::err(Log::ESTATIC, "static call to non-static method {$clazz->getFQSEN()}::{$method_name}()" . " defined at {$method->getContext()->getFile()}:{$method->getContext()->getLineNumberStart()}", $this->context->getFile(), $node->lineno);
         }
         // Make sure the parameters look good
         $this->analyzeCallToMethod($this->code_base, $method, $node);
     } catch (CodeBaseException $exception) {
         Log::err(Log::EUNDEF, $exception->getMessage(), $this->context->getFile(), $node->lineno);
         return $this->context;
     } catch (NodeException $exception) {
         // If we can't figure out what kind of a call
         // this is, don't worry about it
         return $this->context;
     }
     return $this->context;
 }
Пример #3
0
 /**
  * Visit a node with kind `\ast\AST_CLASS_CONST`
  *
  * @param Node $node
  * A node of the type indicated by the method name that we'd
  * like to figure out the type that it produces.
  *
  * @return UnionType
  * The set of types that are possibly produced by the
  * given node
  */
 public function visitClassConst(Node $node) : UnionType
 {
     $constant_name = $node->children['const'];
     if ($constant_name == 'class') {
         return StringType::instance()->asUnionType();
         // class name fetch
     }
     try {
         $defining_clazz = AST::classFromNodeInContext($node, $this->context, $this->code_base, false);
     } catch (CodeBaseException $exception) {
         $class_name = $node->children['class']->children['name'] ?? '';
         Log::err(Log::EUNDEF, "Can't access constant {$constant_name} from undeclared class {$class_name}", $this->context->getFile(), $node->lineno);
         return new UnionType();
     } catch (NodeException $exception) {
         $class_name = $node->children['class']->children['name'] ?? '';
         Log::err(Log::EUNDEF, "Can't access constant {$constant_name} from undeclared class {$class_name}", $this->context->getFile(), $node->lineno);
         // If we can't figure out what kind of a call
         // this is, don't worry about it
         return new UnionType();
     }
     if (!$defining_clazz->hasConstantWithName($this->code_base, $constant_name)) {
         Log::err(Log::EUNDEF, "Can't access undeclared constant {$defining_clazz->getName()}::{$constant_name}", $this->context->getFile(), $node->lineno);
         return new UnionType();
     }
     return $defining_clazz->getConstantWithName($this->code_base, $constant_name)->getUnionType();
 }