fromStringInContext() public static méthode

public static fromStringInContext ( string $type_string, Context $context ) : UnionType
$type_string string A '|' delimited string representing a type in the form 'int|string|null|ClassName'.
$context Context The context in which the type string was found
Résultat UnionType
Exemple #1
0
 /**
  * @return Func[]
  * One or more (alternate) methods begotten from
  * reflection info and internal method data
  */
 public static function functionListFromSignature(CodeBase $code_base, FullyQualifiedFunctionName $fqsen, array $signature) : array
 {
     $context = new Context();
     $return_type = UnionType::fromStringInContext(array_shift($signature), $context);
     $func = new Func($context, $fqsen->getName(), $return_type, 0, $fqsen);
     return self::functionListFromFunction($func, $code_base);
 }
Exemple #2
0
 /**
  * Visit a node with kind `\ast\AST_CLASS`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitClass(Node $node) : Context
 {
     if ($node->flags & \ast\flags\CLASS_ANONYMOUS) {
         $class_name = AST::unqualifiedNameForAnonymousClassNode($node, $this->context);
     } else {
         $class_name = $node->name;
     }
     // This happens now and then and I have no idea
     // why.
     if (empty($class_name)) {
         return $this->context;
     }
     assert(!empty($class_name), "Class must have name in {$this->context}");
     $class_fqsen = FullyQualifiedClassName::fromStringInContext($class_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasClassWithFQSEN($class_fqsen)) {
         $class_fqsen = $class_fqsen->withAlternateId(++$alternate_id);
     }
     // Build the class from what we know so far
     $clazz = new Clazz($this->context->withLineNumberStart($node->lineno ?? 0)->withLineNumberEnd($node->endLineno ?? -1), $class_name, UnionType::fromStringInContext($class_name, $this->context), $node->flags ?? 0);
     // Override the FQSEN with the found alternate ID
     $clazz->setFQSEN($class_fqsen);
     // Add the class to the code base as a globally
     // accessible object
     $this->code_base->addClass($clazz);
     // Look to see if we have a parent class
     if (!empty($node->children['extends'])) {
         $parent_class_name = $node->children['extends']->children['name'];
         // Check to see if the name isn't fully qualified
         if ($node->children['extends']->flags & \ast\flags\NAME_NOT_FQ) {
             if ($this->context->hasNamespaceMapFor(T_CLASS, $parent_class_name)) {
                 // Get a fully-qualified name
                 $parent_class_name = (string) $this->context->getNamespaceMapFor(T_CLASS, $parent_class_name);
             } else {
                 $parent_class_name = $this->context->getNamespace() . '\\' . $parent_class_name;
             }
         }
         // The name is fully qualified. Make sure it looks
         // like it is
         if (0 !== strpos($parent_class_name, '\\')) {
             $parent_class_name = '\\' . $parent_class_name;
         }
         $parent_fqsen = FullyQualifiedClassName::fromStringInContext($parent_class_name, $this->context);
         // Set the parent for the class
         $clazz->setParentClassFQSEN($parent_fqsen);
     }
     // Add any implemeneted interfaces
     if (!empty($node->children['implements'])) {
         $interface_list = AST::qualifiedNameList($this->context, $node->children['implements']);
         foreach ($interface_list as $name) {
             $clazz->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString($name));
         }
     }
     // Update the context to signal that we're now
     // within a class context.
     $context = $clazz->getContext()->withClassFQSEN($class_fqsen);
     return $context;
 }
Exemple #3
0
 /**
  * @param CodeBase $code_base
  * A reference to the entire code base in which this
  * context exists
  *
  * @param ReflectionClass $class
  * A reflection class representing a builtin class.
  *
  * @return Clazz
  * A Class structural element representing the given named
  * builtin.
  */
 public static function fromReflectionClass(CodeBase $code_base, \ReflectionClass $class) : Clazz
 {
     // Build a set of flags based on the constitution
     // of the built-in class
     $flags = 0;
     if ($class->isFinal()) {
         $flags = \ast\flags\CLASS_FINAL;
     } else {
         if ($class->isInterface()) {
             $flags = \ast\flags\CLASS_INTERFACE;
         } else {
             if ($class->isTrait()) {
                 $flags = \ast\flags\CLASS_TRAIT;
             }
         }
     }
     if ($class->isAbstract()) {
         $flags |= \ast\flags\CLASS_ABSTRACT;
     }
     $context = new Context();
     // Build a base class element
     $clazz = new Clazz($context, $class->getName(), UnionType::fromStringInContext($class->getName(), $context), $flags);
     // If this class has a parent class, add it to the
     // class info
     if ($parent_class = $class->getParentClass()) {
         $parent_class_fqsen = FullyQualifiedClassName::fromFullyQualifiedString('\\' . $parent_class->getName());
         $clazz->setParentClassFQSEN($parent_class_fqsen);
     }
     foreach ($class->getDefaultProperties() as $name => $value) {
         // TODO: whats going on here?
         $reflection_property = new \ReflectionProperty($class->getName(), $name);
         $property = new Property($context->withClassFQSEN($clazz->getFQSEN()), $name, Type::fromObject($value)->asUnionType(), 0);
         $clazz->addProperty($code_base, $property);
     }
     foreach ($class->getInterfaceNames() as $name) {
         $clazz->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString('\\' . $name));
     }
     foreach ($class->getTraitNames() as $name) {
         $clazz->addTraitFQSEN(FullyQualifiedClassName::fromFullyQualifiedString('\\' . $name));
     }
     foreach ($class->getConstants() as $name => $value) {
         $clazz->addConstant($code_base, new Constant($context, $name, Type::fromObject($value)->asUnionType(), 0));
     }
     foreach ($class->getMethods() as $reflection_method) {
         $method_list = Method::methodListFromReflectionClassAndMethod($context->withClassFQSEN($clazz->getFQSEN()), $code_base, $class, $reflection_method);
         foreach ($method_list as $method) {
             $clazz->addMethod($code_base, $method);
         }
     }
     return $clazz;
 }
 /**
  * @param CodeBase $code_base
  * The code base within which we're operating
  *
  * @param $context $context
  * The context of the parser at the node for which we'd
  * like to determine a type
  *
  * @param Node|mixed $node
  * The node for which we'd like to determine its type
  *
  * @return UnionType
  * The UnionType associated with the given node
  * in the given Context within the given CodeBase
  *
  * @return UnionType
  * The union type for a node of type \ast\AST_CLASS
  */
 public static function unionTypeFromClassNode(CodeBase $code_base, Context $context, $node) : UnionType
 {
     // For simple nodes or very complicated nodes,
     // recurse
     if (!$node instanceof \ast\Node || $node->kind != \ast\AST_NAME) {
         return self::unionTypeFromNode($code_base, $context, $node);
     }
     $class_name = $node->children['name'];
     // Check to see if the name is fully qualified
     if (!($node->flags & \ast\flags\NAME_NOT_FQ)) {
         if (0 !== strpos($class_name, '\\')) {
             $class_name = '\\' . $class_name;
         }
         return UnionType::fromFullyQualifiedString($class_name);
     }
     if ('parent' === $class_name) {
         $class = $context->getClassInScope($code_base);
         $parent_class_fqsen = $class->getParentClassFQSEN();
         $parent_class = $code_base->getClassByFQSEN($parent_class_fqsen);
         return $parent_class->getUnionType();
     }
     return UnionType::fromStringInContext($class_name, $context);
 }
Exemple #5
0
 /**
  * @param CodeBase $code_base
  * The code base within which we're operating
  *
  * @param $context $context
  * The context of the parser at the node for which we'd
  * like to determine a type
  *
  * @param Node|mixed $node
  * The node for which we'd like to determine its type
  *
  * @return UnionType
  * The UnionType associated with the given node
  * in the given Context within the given CodeBase
  *
  * @throws IssueException
  * An exception is thrown if we can't find a class for
  * the given type
  */
 public static function unionTypeFromClassNode(CodeBase $code_base, Context $context, $node) : UnionType
 {
     // For simple nodes or very complicated nodes,
     // recurse
     if (!$node instanceof \ast\Node || $node->kind != \ast\AST_NAME) {
         return self::unionTypeFromNode($code_base, $context, $node);
     }
     $class_name = $node->children['name'];
     // Check to see if the name is fully qualified
     if (!($node->flags & \ast\flags\NAME_NOT_FQ)) {
         if (0 !== strpos($class_name, '\\')) {
             $class_name = '\\' . $class_name;
         }
         return UnionType::fromFullyQualifiedString($class_name);
     }
     if ('parent' === $class_name) {
         if (!$context->isInClassScope()) {
             throw new IssueException(Issue::fromType(Issue::ContextNotObject)($context->getFile(), $node->lineno ?? 0, [$class_name]));
         }
         $class = $context->getClassInScope($code_base);
         if ($class->isTrait()) {
             throw new IssueException(Issue::fromType(Issue::TraitParentReference)($context->getFile(), $node->lineno ?? 0, [(string) $context->getClassFQSEN()]));
         }
         if (!$class->hasParentClassFQSEN()) {
             throw new IssueException(Issue::fromType(Issue::ParentlessClass)($context->getFile(), $node->lineno ?? 0, [(string) $context->getClassFQSEN()]));
         }
         $parent_class_fqsen = $class->getParentClassFQSEN();
         if (!$code_base->hasClassWithFQSEN($parent_class_fqsen)) {
             throw new IssueException(Issue::fromType(Issue::UndeclaredClass)($context->getFile(), $node->lineno ?? 0, [(string) $parent_class_fqsen]));
         } else {
             $parent_class = $code_base->getClassByFQSEN($parent_class_fqsen);
             return $parent_class->getUnionType();
         }
     }
     return UnionType::fromStringInContext($class_name, $context);
 }
Exemple #6
0
 /**
  * A list of types for parameters associated with the
  * given builtin function with the given name
  *
  * @param FullyQualifiedMethodName|FullyQualifiedFunctionName $function_fqsen
  *
  * @see internal_varargs_check
  * Formerly `function internal_varargs_check`
  */
 public static function internalFunctionSignatureMapForFQSEN($function_fqsen) : array
 {
     $context = new Context();
     $map = self::internalFunctionSignatureMap();
     if ($function_fqsen instanceof FullyQualifiedMethodName) {
         $class_fqsen = $function_fqsen->getFullyQualifiedClassName();
         $class_name = $class_fqsen->getName();
         $function_name = $class_name . '::' . $function_fqsen->getName();
     } else {
         $function_name = $function_fqsen->getName();
     }
     $function_name_original = $function_name;
     $alternate_id = 0;
     $configurations = [];
     while (isset($map[$function_name])) {
         // Get some static data about the function
         $type_name_struct = $map[$function_name];
         if (empty($type_name_struct)) {
             continue;
         }
         // Figure out the return type
         $return_type_name = array_shift($type_name_struct);
         $return_type = $return_type_name ? UnionType::fromStringInContext($return_type_name, $context) : null;
         $name_type_name_map = $type_name_struct;
         $property_name_type_map = [];
         foreach ($name_type_name_map as $name => $type_name) {
             $property_name_type_map[$name] = empty($type_name) ? new UnionType() : UnionType::fromStringInContext($type_name, $context);
         }
         $configurations[] = ['return_type' => $return_type, 'property_name_type_map' => $property_name_type_map];
         $function_name = $function_name_original . '\'' . ++$alternate_id;
     }
     return $configurations;
 }
Exemple #7
0
 /**
  * @param Context $context
  * The context in which the comment line appears
  *
  * @param string $line
  * An individual line of a comment
  *
  * @return CommentParameter
  * A CommentParameter associated with a line that has a var
  * or param reference.
  */
 private static function parameterFromCommentLine(Context $context, string $line)
 {
     $match = [];
     if (preg_match('/@(param|var)\\s+(' . UnionType::union_type_regex . ')(\\s+(\\$\\S+))?/', $line, $match)) {
         $type = $match[2];
         $variable_name = empty($match[23]) ? '' : trim($match[23], '$');
         // If the type looks like a variable name, make it an
         // empty type so that other stuff can match it. We can't
         // just skip it or we'd mess up the parameter order.
         $union_type = null;
         if (0 !== strpos($type, '$')) {
             $union_type = UnionType::fromStringInContext($type, $context);
         } else {
             $union_type = new UnionType();
         }
         return new CommentParameter($variable_name, $union_type);
     }
     return new CommentParameter('', new UnionType());
 }
Exemple #8
0
 /**
  * @return UnionType|null
  * Returns UnionType (Possible with empty set) if and only if isHardcodedGlobalVariableWithName is true.
  * Returns null otherwise.
  */
 public static function getUnionTypeOfHardcodedGlobalVariableWithName(string $name, Context $context)
 {
     if (array_key_exists($name, self::_BUILTIN_SUPERGLOBAL_TYPES)) {
         // More efficient than using context.
         return UnionType::fromFullyQualifiedString(self::_BUILTIN_SUPERGLOBAL_TYPES[$name]);
     }
     if (array_key_exists($name, Config::get()->globals_type_map) || in_array($name, Config::get()->runkit_superglobals)) {
         $type_string = Config::get()->globals_type_map[$name] ?? '';
         return UnionType::fromStringInContext($type_string, $context);
     }
     return null;
 }
Exemple #9
0
 /**
  * @return bool
  * False if the class name doesn't point to a known class
  */
 private function classExistsOrIsNative(Node $node) : bool
 {
     if ($this->classExists()) {
         return true;
     }
     $type = UnionType::fromStringInContext($this->class_name, $this->context);
     if ($type->isNativeType()) {
         return true;
     }
     Log::err(Log::EUNDEF, "reference to undeclared class {$this->class_fqsen}", $this->context->getFile(), $node->lineno);
     return false;
 }
Exemple #10
0
 /**
  * @return Comment
  * A comment built by parsing the given doc block
  * string.
  */
 public static function fromStringInContext(string $comment, Context $context) : Comment
 {
     $is_deprecated = false;
     $variable_list = [];
     $parameter_list = [];
     $return = null;
     // A legal type identifier
     $simple_type_regex = '[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*';
     // A legal type identifier optionally with a []
     // indicating that its a generic typed array
     $generic_array_type_regex = "{$simple_type_regex}(\\[\\])?";
     // A list of one or more types delimited by the '|'
     // character
     $union_type_regex = "{$generic_array_type_regex}(\\|{$generic_array_type_regex})*";
     $lines = explode("\n", $comment);
     foreach ($lines as $line) {
         if (($pos = strpos($line, '@param')) !== false) {
             $match = [];
             if (preg_match("/@param\\s+({$union_type_regex})(\\s+(\\\$\\S+))?/", $line, $match)) {
                 $type = null;
                 if (stripos($match[1], '\\') === 0 && strpos($match[1], '\\', 1) === false) {
                     $type = trim($match[1], '\\');
                 } else {
                     $type = $match[1];
                 }
                 $variable_name = empty($match[6]) ? '' : trim($match[6], '$');
                 // If the type looks like a variable name,
                 // make it an empty type so that other stuff
                 // can match it. We can't just skip it or
                 // we'd mess up the parameter order.
                 $union_type = null;
                 if (0 !== strpos($type, '$')) {
                     $union_type = UnionType::fromStringInContext($type, $context);
                 } else {
                     $union_type = new UnionType();
                 }
                 $comment_parameter = new CommentParameter($variable_name, $union_type, $line);
             } else {
                 $comment_parameter = new CommentParameter('', new UnionType(), $line);
             }
             $parameter_list[] = $comment_parameter;
         }
         if (($pos = stripos($line, '@var')) !== false) {
             $match = [];
             if (preg_match("/@var\\s+({$union_type_regex})\\s*(?:(\\S+))*/", $line, $match)) {
                 $type = null;
                 if (strpos($match[1], '\\') === 0 && strpos($match[1], '\\', 1) === false) {
                     $type = trim($match[1], '\\');
                 } else {
                     $type = $match[1];
                 }
                 $var_name = empty($match[2]) ? '' : trim($match[2], '$');
                 $var_type = UnionType::fromStringInContext($type, $context);
                 $comment_parameter = new CommentParameter($var_name, $var_type, $line);
             } else {
                 $comment_parameter = new CommentParameter('', new UnionType(), $line);
             }
             $variable_list[] = $comment_parameter;
         }
         if (($pos = stripos($line, '@return')) !== false) {
             $match = [];
             if (preg_match("/@return\\s+({$union_type_regex}+)/", $line, $match)) {
                 if (strpos($match[1], '\\') === 0 && strpos($match[1], '\\', 1) === false) {
                     $return = trim($match[1], '\\');
                 } else {
                     $return = $match[1];
                 }
             }
         }
         if (($pos = stripos($line, '@deprecated')) !== false) {
             if (preg_match('/@deprecated\\b/', $line, $match)) {
                 $is_deprecated = true;
             }
         }
     }
     $return_type = UnionType::fromStringInContext($return ?: '', $context);
     return new Comment($is_deprecated, $variable_list, $parameter_list, $return_type);
 }
Exemple #11
0
 /**
  * Get a fully qualified name form a node
  *
  * @return string
  *
  * @see \Phan\Deprecated\Util::qualified_name
  * From `function qualified_name`
  */
 public static function qualifiedName(Context $context, $node) : string
 {
     if (!$node instanceof \ast\Node || $node->kind != \ast\AST_NAME) {
         return (string) self::varUnionType($context, $node);
     }
     $type_name = $node->children['name'];
     $type = null;
     // Check to see if the name is fully qualified
     if (!($node->flags & \ast\flags\NAME_NOT_FQ)) {
         if (0 !== strpos($type_name, '\\')) {
             $type_name = '\\' . $type_name;
         }
         return (string) UnionType::fromFullyQualifiedString($type_name);
     }
     $type = UnionType::fromStringInContext($type_name, $context);
     return (string) $type;
 }
Exemple #12
0
 /**
  * @return Method[]
  * One or more (alternate) methods begotten from
  * reflection info and internal method data
  */
 public static function methodListFromSignature(CodeBase $code_base, FullyQualifiedFunctionName $fqsen, array $signature) : array
 {
     $context = new Context();
     $return_type = UnionType::fromStringInContext(array_shift($signature), $context);
     $method = new Method($context, $fqsen->getName(), $return_type, 0);
     $method->setFQSEN($fqsen);
     return self::methodListFromMethod($method, $code_base);
 }
Exemple #13
0
 /**
  * @param CodeBase $code_base
  * A reference to the entire code base in which this
  * context exists
  *
  * @param ReflectionClass $class
  * A reflection class representing a builtin class.
  *
  * @return Clazz
  * A Class structural element representing the given named
  * builtin.
  */
 public static function fromReflectionClass(CodeBase $code_base, \ReflectionClass $class) : Clazz
 {
     // Build a set of flags based on the constitution
     // of the built-in class
     $flags = 0;
     if ($class->isFinal()) {
         $flags = \ast\flags\CLASS_FINAL;
     } elseif ($class->isInterface()) {
         $flags = \ast\flags\CLASS_INTERFACE;
     } elseif ($class->isTrait()) {
         $flags = \ast\flags\CLASS_TRAIT;
     }
     if ($class->isAbstract()) {
         $flags |= \ast\flags\CLASS_ABSTRACT;
     }
     $context = new Context();
     $class_fqsen = FullyQualifiedClassName::fromStringInContext($class->getName(), $context);
     // Build a base class element
     $clazz = new Clazz($context, $class->getName(), UnionType::fromStringInContext($class->getName(), $context), $flags, $class_fqsen);
     // If this class has a parent class, add it to the
     // class info
     if ($parent_class = $class->getParentClass()) {
         $parent_class_fqsen = FullyQualifiedClassName::fromFullyQualifiedString('\\' . $parent_class->getName());
         $parent_type = $parent_class_fqsen->asType();
         $clazz->setParentType($parent_type);
     }
     // n.b.: public properties on internal classes don't get
     //       listed via reflection until they're set unless
     //       they have a default value. Therefore, we don't
     //       bother iterating over `$class->getProperties()`
     //       `$class->getStaticProperties()`.
     foreach ($class->getDefaultProperties() as $name => $value) {
         $property_context = $context->withScope(new ClassScope(new GlobalScope(), $clazz->getFQSEN()));
         $property_fqsen = FullyQualifiedPropertyName::make($clazz->getFQSEN(), $name);
         $property = new Property($property_context, $name, Type::fromObject($value)->asUnionType(), 0, $property_fqsen);
         $clazz->addProperty($code_base, $property, new None());
     }
     foreach (UnionType::internalPropertyMapForClassName($clazz->getName()) as $property_name => $property_type_string) {
         $property_context = $context->withScope(new ClassScope(new GlobalScope(), $clazz->getFQSEN()));
         $property_type = UnionType::fromStringInContext($property_type_string, new Context());
         $property_fqsen = FullyQualifiedPropertyName::make($clazz->getFQSEN(), $property_name);
         $property = new Property($property_context, $property_name, $property_type, 0, $property_fqsen);
         $clazz->addProperty($code_base, $property, new None());
     }
     foreach ($class->getInterfaceNames() as $name) {
         $clazz->addInterfaceClassFQSEN(FullyQualifiedClassName::fromFullyQualifiedString('\\' . $name));
     }
     foreach ($class->getTraitNames() as $name) {
         $clazz->addTraitFQSEN(FullyQualifiedClassName::fromFullyQualifiedString('\\' . $name));
     }
     foreach ($class->getConstants() as $name => $value) {
         $constant_fqsen = FullyQualifiedClassConstantName::make($clazz->getFQSEN(), $name);
         $constant = new ClassConstant($context, $name, Type::fromObject($value)->asUnionType(), 0, $constant_fqsen);
         $clazz->addConstant($code_base, $constant);
     }
     foreach ($class->getMethods() as $reflection_method) {
         $method_context = $context->withScope(new ClassScope(new GlobalScope(), $clazz->getFQSEN()));
         $method_list = FunctionFactory::methodListFromReflectionClassAndMethod($method_context, $code_base, $class, $reflection_method);
         foreach ($method_list as $method) {
             $clazz->addMethod($code_base, $method, new None());
         }
     }
     return $clazz;
 }