addType() public method

Add a type name to the list of types
public addType ( Type $type ) : void
$type Type
return void
Esempio n. 1
0
 /**
  * @param CodeBase
  * The code base to use in order to find super classes, etc.
  *
  * @param $recursion_depth
  * This thing has a tendency to run-away on me. This tracks
  * how bad I messed up by seeing how far the expanded types
  * go
  *
  * @return UnionType
  * Expands class types to all inherited classes returning
  * a superset of this type.
  */
 public function asExpandedTypes(CodeBase $code_base, int $recursion_depth = 0) : UnionType
 {
     return $this->memoize(__METHOD__, function () use($code_base, $recursion_depth) : UnionType {
         // We're going to assume that if the type hierarchy
         // is taller than some value we probably messed up
         // and should bail out.
         assert($recursion_depth < 20, "Recursion has gotten out of hand for type {$this}");
         if ($this->isNativeType()) {
             return $this->asUnionType();
         }
         $union_type = $this->asUnionType();
         $class_fqsen = $this->isGenericArray() ? $this->genericArrayElementType()->asFQSEN() : $this->asFQSEN();
         if (!$code_base->hasClassWithFQSEN($class_fqsen)) {
             return $union_type;
         }
         $clazz = $code_base->getClassByFQSEN($class_fqsen);
         $union_type->addUnionType($this->isGenericArray() ? $clazz->getUnionType()->asGenericArrayTypes() : $clazz->getUnionType());
         // Resurse up the tree to include all types
         $recursive_union_type = new UnionType();
         foreach ($union_type->getTypeSet() as $clazz_type) {
             if ((string) $clazz_type != (string) $this) {
                 $recursive_union_type->addUnionType($clazz_type->asExpandedTypes($code_base, $recursion_depth + 1));
             } else {
                 $recursive_union_type->addType($clazz_type);
             }
         }
         return $recursive_union_type;
     });
 }
Esempio n. 2
0
 /**
  * Visit a node with kind `\ast\AST_DIM`
  *
  * @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 visitDim(Node $node) : UnionType
 {
     $union_type = self::unionTypeFromNode($this->code_base, $this->context, $node->children['expr']);
     if ($union_type->isEmpty()) {
         return $union_type;
     }
     // Figure out what the types of accessed array
     // elements would be
     $generic_types = $union_type->genericArrayElementTypes();
     // If we have generics, we're all set
     if (!$generic_types->isEmpty()) {
         return $generic_types;
     }
     // If the only type is null, we don't know what
     // accessed items will be
     if ($union_type->isType(NullType::instance())) {
         return new UnionType();
     }
     $element_types = new UnionType();
     // You can access string characters via array index,
     // so we'll add the string type to the result if we're
     // indexing something that could be a string
     if ($union_type->isType(StringType::instance()) || $union_type->canCastToUnionType(StringType::instance()->asUnionType())) {
         $element_types->addType(StringType::instance());
     }
     // array offsets work on strings, unfortunately
     // Double check that any classes in the type don't
     // have ArrayAccess
     $array_access_type = Type::fromNamespaceAndName('\\', 'ArrayAccess');
     // Hunt for any types that are viable class names and
     // see if they inherit from ArrayAccess
     foreach ($union_type->getTypeList() as $type) {
         if ($type->isNativeType()) {
             continue;
         }
         $class_fqsen = FullyQualifiedClassName::fromType($type);
         // If we can't find the class, the type probably
         // wasn't a class.
         if (!$this->code_base->hasClassWithFQSEN($class_fqsen)) {
             continue;
         }
         $class = $this->code_base->getClassByFQSEN($class_fqsen);
         // If the class has type ArrayAccess, it can be indexed
         // as if it were an array. That being said, we still don't
         // know the types of the elements, but at least we don't
         // error out.
         if ($class->getUnionType()->hasType($array_access_type)) {
             return $element_types;
         }
     }
     if ($element_types->isEmpty()) {
         Log::err(Log::ETYPE, "Suspicious array access to {$union_type}", $this->context->getFile(), $node->lineno);
     }
     return $element_types;
 }
Esempio n. 3
0
 /**
  * @param CodeBase
  * The code base to use in order to find super classes, etc.
  *
  * @param $recursion_depth
  * This thing has a tendency to run-away on me. This tracks
  * how bad I messed up by seeing how far the expanded types
  * go
  *
  * @return UnionType
  * Expands class types to all inherited classes returning
  * a superset of this type.
  */
 public function asExpandedTypes(CodeBase $code_base, int $recursion_depth = 0) : UnionType
 {
     return $this->memoize(__METHOD__, function () use($code_base, $recursion_depth) : UnionType {
         assert($recursion_depth < 10, "Recursion has gotten out of hand for type {$this}");
         if ($this->isNativeType()) {
             return $this->asUnionType();
         }
         $union_type = $this->asUnionType();
         $class_fqsen = $this->isGenericArray() ? $this->genericArrayElementType()->asFQSEN() : $this->asFQSEN();
         if (!$code_base->hasClassWithFQSEN($class_fqsen)) {
             return $union_type;
         }
         $clazz = $code_base->getClassByFQSEN($class_fqsen);
         $union_type->addUnionType($this->isGenericArray() ? $clazz->getUnionType()->asGenericArrayTypes() : $clazz->getUnionType());
         // Resurse up the tree to include all types
         $recursive_union_type = new UnionType();
         foreach ($union_type->getTypeList() as $clazz_type) {
             if ((string) $clazz_type != (string) $this) {
                 $recursive_union_type->addUnionType($clazz_type->asExpandedTypes($code_base, $recursion_depth + 1));
             } else {
                 $recursive_union_type->addType($clazz_type);
             }
         }
         return $recursive_union_type;
     });
 }
Esempio n. 4
0
 /**
  * Visit a node with kind `\ast\AST_DIM`
  *
  * @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 visitDim(Node $node) : UnionType
 {
     $union_type = self::unionTypeFromNode($this->code_base, $this->context, $node->children['expr']);
     if ($union_type->isEmpty()) {
         return $union_type;
     }
     // Figure out what the types of accessed array
     // elements would be
     $generic_types = $union_type->genericArrayElementTypes();
     // If we have generics, we're all set
     if (!$generic_types->isEmpty()) {
         return $generic_types;
     }
     // If the only type is null, we don't know what
     // accessed items will be
     if ($union_type->isType(NullType::instance())) {
         return new UnionType();
     }
     $element_types = new UnionType();
     // You can access string characters via array index,
     // so we'll add the string type to the result if we're
     // indexing something that could be a string
     if ($union_type->isType(StringType::instance()) || $union_type->canCastToUnionType(StringType::instance()->asUnionType())) {
         $element_types->addType(StringType::instance());
     }
     // array offsets work on strings, unfortunately
     // Double check that any classes in the type don't
     // have ArrayAccess
     $array_access_type = Type::fromNamespaceAndName('\\', 'ArrayAccess');
     // Hunt for any types that are viable class names and
     // see if they inherit from ArrayAccess
     try {
         foreach ($union_type->asClassList($this->code_base) as $class) {
             if ($class->getUnionType()->hasType($array_access_type)) {
                 return $element_types;
             }
         }
     } catch (CodeBaseException $exception) {
         // Swallow it
     }
     if ($element_types->isEmpty()) {
         $this->emitIssue(Issue::TypeArraySuspicious, $node->lineno ?? 0, (string) $union_type);
     }
     return $element_types;
 }
Esempio n. 5
0
 /**
  * Takes "a|b[]|c|d[]|e" and returns "b|d"
  *
  * @return UnionType
  * The subset of types in this
  */
 public function genericArrayElementTypes() : UnionType
 {
     $union_type = new UnionType($this->type_set->filter(function (Type $type) : bool {
         return $type->isGenericArray();
     })->map(function (Type $type) : Type {
         return $type->genericArrayElementType();
     }));
     // If array is in there, then it can be any type
     // Same for mixed
     if ($this->hasType(ArrayType::instance()) || $this->hasType(MixedType::instance())) {
         $union_type->addType(MixedType::instance());
     }
     if ($this->hasType(ArrayType::instance())) {
         $union_type->addType(NullType::instance());
     }
     return $union_type;
 }