示例#1
0
 public function leaveNode(Node $node)
 {
     if (!$node instanceof Expr) {
         return;
     }
     $type = null;
     if ($node instanceof Expr\Assign || $node instanceof Expr\AssignRef) {
         $type = $node->expr->getAttribute('type');
     } elseif ($node instanceof Expr\Ternary) {
         $exprType1 = $node->if === null ? $node->cond->getAttribute('type') : $node->if->getAttribute('type');
         $exprType2 = $node->else->getAttribute('type');
         $type = Type::alternatives([$exprType1, $exprType2]);
     } elseif ($node instanceof Expr\BinaryOp\Coalesce) {
         $exprType1 = $node->left->getAttribute('type');
         $exprType2 = $node->right->getAttribute('type');
         $type = Type::alternatives([$exprType1, $exprType2]);
     } elseif ($node instanceof Expr\ErrorSuppress) {
         $type = $node->expr->getAttribute('type');
     } elseif ($node instanceof Expr\Eval_) {
         $type = Type::mixed_();
     } elseif ($node instanceof Expr\Exit_) {
         $type = Type::null_();
     }
     if ($type !== null || !$node->hasAttribute('type')) {
         if ($type === null) {
             $type = Type::mixed_();
         }
         $node->setAttribute('type', $type);
     }
 }
示例#2
0
 protected function makeMethod($name, $visibility = ClassLike::M_PUBLIC)
 {
     return (new Method())->setName($name)->setReturnType(Type::mixed_())->setDocReturnType(Type::mixed_())->setAccessibility($visibility);
 }
示例#3
0
 /**
  * @param ClassLike      $class
  * @param Stmt\ClassLike $node
  */
 protected function processClassLike(ClassLike $class, Stmt\ClassLike $node)
 {
     $this->init($class, $node);
     foreach ($node->stmts as $child) {
         if ($child instanceof Stmt\ClassConst) {
             foreach ($child->consts as $constNode) {
                 $const = new ClassConst();
                 $this->init($const, $constNode);
                 $const->setClass($class);
                 $class->addConst($const);
             }
         } elseif ($child instanceof Stmt\Property) {
             $annotations = [];
             if ($child->hasAttribute('annotations')) {
                 $annotations = $child->getAttribute('annotations');
             }
             $docTypes = [];
             if (!empty($annotations['var'])) {
                 foreach ($annotations['var'] as $varTag) {
                     $docTypes[$varTag->getIdentifier()] = $varTag->getType();
                 }
             }
             foreach ($child->props as $propertyNode) {
                 $property = new Property();
                 $this->init($property, $propertyNode);
                 $property->setName('$' . $property->getName());
                 $this->processMember($property, $child, $class);
                 $type = Type::mixed_();
                 if (!empty($docTypes[$property->getName()])) {
                     $type = $docTypes[$property->getName()];
                 } elseif (count($child->props) === 1 && !empty($docTypes[null])) {
                     $type = $docTypes[null];
                 }
                 $property->setType($type);
                 $class->addProperty($property);
             }
         } elseif ($child instanceof Stmt\ClassMethod) {
             $method = new Method();
             $this->processFunction($method, $child);
             $this->processMember($method, $child, $class);
             $method->setAbstract($child->isAbstract());
             $method->setFinal($child->isFinal());
             $class->addMethod($method);
         }
     }
 }
示例#4
0
 public function leaveNode(Node $node)
 {
     if ($node instanceof Stmt\Function_ || $node instanceof Stmt\ClassMethod || $node instanceof Expr\Closure) {
         array_pop($this->functionScopeStack);
     } elseif ($node instanceof Stmt\ClassLike) {
         array_pop($this->classStack);
         array_pop($this->functionScopeStack);
     }
     if (!$node instanceof Expr) {
         return;
     }
     $type = null;
     $reflections = null;
     if ($node instanceof Expr\Variable) {
         if (is_string($node->name)) {
             if ($node->name === 'this') {
                 $type = $this->getCurrentClass();
             } elseif (array_key_exists('$' . $node->name, $this->getCurrentFunctionScope())) {
                 $type = $this->getCurrentFunctionScope()['$' . $node->name];
             }
         }
     } elseif ($node instanceof Expr\FuncCall) {
         $reflections = [];
         if ($node->name instanceof Name) {
             $reflections = $this->reflection->findFunction(Type::nameToString($node->name));
         } else {
             $reflections = $this->findMethods($node->name->getAttribute('type'), '__invoke');
         }
         $type = $this->functionsReturnType($reflections);
         // TODO: ConstFetch
     } elseif ($node instanceof Expr\MethodCall) {
         $reflections = [];
         if (is_string($node->name) || $node->name instanceof Identifier) {
             $reflections = $this->findMethods($node->var->getAttribute('type'), (string) $node->name);
         }
         $type = $this->functionsReturnType($reflections);
     } elseif ($node instanceof Expr\StaticCall) {
         $reflections = [];
         if ($node->class instanceof Name && (is_string($node->name) || $node->name instanceof Identifier)) {
             $reflections = $this->findMethods(Type::object_(Type::nameToString($node->class)), (string) $node->name, true);
         }
         $type = $this->functionsReturnType($reflections);
     } elseif ($node instanceof Expr\PropertyFetch) {
         $reflections = [];
         if (is_string($node->name) || $node->name instanceof Identifier) {
             $reflections = $this->findProperties($node->var->getAttribute('type'), '$' . (string) $node->name);
         }
         $type = $this->variablesType($reflections);
     } elseif ($node instanceof Expr\StaticPropertyFetch) {
         $reflections = [];
         if ($node->class instanceof Name && is_string($node->name)) {
             $reflections = $this->findProperties(Type::object_(Type::nameToString($node->class)), '$' . $node->name, true);
         }
         $type = $this->variablesType($reflections);
     } elseif ($node instanceof Expr\ClassConstFetch) {
         // TODO ::class
         $reflections = [];
         if ($node->class instanceof Name) {
             $reflections = $this->findClassConsts(Type::object_(Type::nameToString($node->class)), (string) $node->name);
         }
         $type = $this->constsType($reflections);
     } elseif ($node instanceof Expr\ArrayDimFetch) {
         $arrayType = $node->var->getAttribute('type');
         $altTypes = [$arrayType];
         if ($arrayType instanceof AlternativesType) {
             $altTypes = $arrayType->getAlternatives();
         }
         $types = [];
         foreach ($altTypes as $altType) {
             if ($altType instanceof ArrayType) {
                 $types[] = $altType->getValueType();
             } elseif ($altType instanceof ObjectType) {
                 $types[] = $this->functionsReturnType($this->findMethods($altType, 'offsetGet'));
                 // TODO: check for ArrayAccess
             }
         }
         $type = $types !== [] ? Type::alternatives($types) : Type::mixed_();
     } elseif ($node instanceof Expr\Array_) {
         $type = Type::array_();
     } elseif ($node instanceof Expr\New_) {
         if ($node->class instanceof Name) {
             $type = Type::object_(Type::nameToString($node->class));
         } else {
             $type = Type::object_();
         }
     } elseif ($node instanceof Expr\Clone_) {
         $type = $node->expr->getAttribute('type');
     } elseif ($node instanceof Expr\Closure) {
         $type = Type::object_('\\Closure');
     } elseif ($node instanceof Expr\Cast\Array_) {
         $exprType = $node->expr->getAttribute('type');
         $altTypes = [$exprType];
         if ($exprType instanceof AlternativesType) {
             $altTypes = $exprType->getAlternatives();
         }
         $types = [];
         foreach ($altTypes as $altType) {
             if ($altType instanceof ArrayType) {
                 $types[] = $altType;
             } else {
                 $types[] = Type::array_();
                 // TODO primitives: (array)int --> int[]
             }
         }
         $type = $types !== [] ? Type::alternatives($types) : Type::mixed_();
     } elseif ($node instanceof Expr\Cast\Object_) {
         $exprType = $node->expr->getAttribute('type');
         $altTypes = [$exprType];
         if ($exprType instanceof AlternativesType) {
             $altTypes = $exprType->getAlternatives();
         }
         $types = [];
         foreach ($altTypes as $altType) {
             if ($altType instanceof ObjectType) {
                 $types[] = $altType;
             } else {
                 $types[] = Type::object_('\\stdClass');
             }
         }
         $type = $types !== [] ? Type::alternatives($types) : Type::mixed_();
     } elseif ($node instanceof Expr\Include_) {
         $type = Type::mixed_();
         // TODO: Yield_
         // TODO: YieldFrom
     }
     if ($type !== null) {
         $node->setAttribute('type', $type);
     }
     if ($reflections !== null) {
         $node->setAttribute('reflections', $reflections);
     }
 }
示例#5
0
 protected function handleFunction(Function_ $function, array $data)
 {
     $this->handleElement($function, $data);
     $function->setReturnType(Type::mixed_());
     $function->setDocReturnType($this->getType($data['return_type']));
     $function->setReturnByRef($data['return_by_ref']);
     foreach ($data['params'] as $paramData) {
         $param = new Param();
         $param->setName($paramData['name']);
         $param->setTypeHint(Type::mixed_());
         $param->setDocType($this->getType($paramData['type']));
         $param->setOptional($paramData['optional']);
         $param->setByRef($paramData['by_ref']);
         $param->setVariadic($paramData['variadic']);
         $function->addParam($param);
     }
 }