public function isSubTypeOf(PhpType $that) { if ($that->isBooleanType()) { return true; } return parent::isSubTypeOf($that); }
private function isSubtype(PhpType $a, PhpType $b) { if ($a->isUnknownType()) { return false; } if (null === ($objType = $a->toMaybeObjectType())) { return false; } return $objType->isSubtypeOf($b); }
public function addAlternate(PhpType $alternate) { // build() returns the bottom type by default, so we can // just bail out early here. if ($alternate->isNoType()) { return $this; } $this->isAllType = $this->isAllType || $alternate->isAllType(); $isAlternateUnknown = $alternate instanceof UnknownType; // instanceof is desired here $this->isNativeUnknownType = $this->isNativeUnknownType || $isAlternateUnknown; if ($isAlternateUnknown) { $this->areAllUnknownsChecked = $this->areAllUnknownsChecked && $alternate->isChecked(); } if (!$this->isAllType && !$this->isNativeUnknownType) { if ($alternate->isUnionType()) { $union = $alternate->toMaybeUnionType(); foreach ($union->getAlternates() as $unionAlt) { $this->addAlternate($unionAlt); } } else { // Look through the alternates we've got so far, // and check if any of them are duplicates of // one another. foreach ($this->alternates as $index => $current) { // The Unknown type is special in that we cannot use our // subtype based check, but need to check for equality to // avoid duplicates, and not remove all other alternates. if ($alternate->isUnknownType()) { if ($alternate->equals($current)) { return $this; } continue; } // Check if we already have a more general type in the union. // Then, we do not add this alternate. if ($alternate->isSubTypeOf($current)) { return $this; } // Check if we have a subtype of the passed alternate. Then, // we remove that alternate in favor of the newly passed one. if ($current->isSubTypeOf($alternate)) { unset($this->alternates[$index]); } } $this->alternates[] = $alternate; } } return $this; }
public function getThisType(PhpType $objType) { switch (true) { case $objType instanceof ProxyObjectType: $className = $objType->getReferenceName(); break; case $objType instanceof MethodContainer: $className = $objType->getName(); break; default: throw new \LogicException(sprintf('The previous CASES were exhaustive. Unknown type "%s".', get_class($objType))); } $loweredClassName = strtolower($className); if (!isset($this->thisTypes[$loweredClassName])) { $this->thisTypes[$loweredClassName] = new ThisType($this, $this->getClassOrCreate($className)); } return $this->thisTypes[$loweredClassName]; }
protected function getRestrictedByGetClassResult(PhpType $type = null, $value, $resultEqualsValue) { if (null === $type) { if ($resultEqualsValue) { return $this->typeRegistry->getClassOrCreate($value); } return null; } return $type->visit(new RestrictByGetClassResultVisitor($this->typeRegistry, $value, $resultEqualsValue)); }
/** * @dataProvider getEqualsTests */ public function testEquals(PhpType $a, PhpType $b, $expectedOutcome) { $this->assertSame($expectedOutcome, $a->equals($b)); }
private function restrictByCallable(PhpType $type = null, $outcome) { if (null === $type) { return $outcome ? $this->typeRegistry->getNativeType('callable') : null; } if ($outcome) { if ($type->isUnknownType() || $type->isAllType()) { return $this->typeRegistry->getNativeType('callable'); } if ($type->isUnionType()) { $types = array(); foreach ($type->getAlternates() as $altType) { if ($altType->canBeCalled()) { $types[] = $altType; } } return $this->typeRegistry->createUnionType($types); } return $type->canBeCalled() ? $type : $this->typeRegistry->getNativeType('none'); } if ($type->isCallableType()) { return $this->typeRegistry->getNativeType('none'); } if ($type->isUnionType()) { $types = array(); foreach ($type->getAlternates() as $altType) { if ($altType->isCallableType()) { continue; } $types[] = $altType; } return $this->typeRegistry->createUnionType($types); } return $type; }
public function isSubtypeOf(PhpType $that) { if (PhpType::isSubTypeOf($that)) { return true; } if ($that->isNoObjectType()) { return true; } if ($that->isCallableType() && (!$this->isNormalized() || $this->hasMethod('__invoke'))) { return true; } if (false === $that->isObjectType()) { return false; } if (false === $this->isNormalized()) { return true; } if ($that->isInterface()) { $name = strtolower($that->toMaybeObjectType()->getName()); foreach ($this->extendedInterfaces as $iName) { if ($name === strtolower($iName)) { return true; } } return false; } if ($that instanceof ProxyObjectType) { $name = strtolower($that->getReferenceName()); foreach ($this->extendedInterfaces as $iName) { if ($name === strtolower($iName)) { return true; } } return false; } return false; }
private function hasTypeChanged(PhpType $newType, PhpType $currentType = null) { if (null === $currentType) { return true; } return false === $newType->equals($currentType); }
/** * Returns whether the passed type is meaningfully different from this type. * * In contrast to ``equals()``, this method treats unknown types specially. * * If no unknown type is involved, then the result of this method is the opposite * boolean result of ``equals()``. * * If unknown types are involved, we regard the types as different if only one * of the involved types is an unknown type. * * TODO: Since the difference between known unknowns (aka checked unknowns), * and unknown unknowns has been removed. This method should be superfluous. * * @see http://www.youtube.com/watch?v=QaxqUDd4fiw&feature=related */ public function differsFrom(PhpType $that) { if (!$this->isUnknownType() && !$that->isUnknownType()) { return !$this->equals($that); } return (bool) ($this->isUnknownType() ^ $that->isUnknownType()); }
/** * Refines an array type with the information about the used key, and assigned element type. * * This also defines the type for the item key if available and non-dynamic. * * @param PhpType $varType * @param PhpType $resultType * @param \PHPParser_Node_Expr_ArrayDimFetch $node * * @return ArrayType */ private function getRefinedArrayType(PhpType $varType, PhpType $resultType, \PHPParser_Node_Expr_ArrayDimFetch $node) { $usedKeyType = $this->getKeyTypeForDimFetch($node); $keyType = $varType->getKeyType(); if ($keyType === $this->typeRegistry->getNativeType('generic_array_key')) { $refinedKeyType = $usedKeyType; } else { $refinedKeyType = $keyType->getLeastSupertype($usedKeyType); } $elementType = $varType->getElementType(); if ($elementType === $this->typeRegistry->getNativeType('generic_array_value')) { $refinedElementType = $resultType; } else { $refinedElementType = $elementType->getLeastSupertype($resultType); } $refinedType = $this->typeRegistry->getArrayType($refinedElementType, $refinedKeyType); // Infer the type of the key if a concrete value is available. NodeUtil::getValue($node->dim)->map(function ($keyName) use(&$refinedType, $resultType) { $refinedType = $refinedType->inferItemType($keyName, $resultType); }); return $refinedType; }
private function getClassName(PhpType $type) { if ($type instanceof NamedType) { return $type->getReferenceName(); } $methodContainer = $type->toMaybeObjectType(); if ($methodContainer instanceof Clazz) { return $methodContainer->getName(); } return null; }
public function equals(PhpType $type) { if ($type->isClass() && strtolower($type->toMaybeObjectType()->getName()) === strtolower($this->getName())) { return true; } if ($type instanceof ProxyObjectType && strtolower($type->getReferenceName()) === strtolower($this->getName())) { return true; } return false; }
private function getStringRepr(PhpType $type) { switch (true) { case $type instanceof AllType: return TypeRegistry::NATIVE_ALL; // This handles the generic array type specially. // This handles the generic array type specially. case $type === self::$typeRegistry->getNativeType('array'): return 'array'; case $type instanceof ArrayType: $itemTypes = $type->getItemTypes(); if (empty($itemTypes)) { return TypeRegistry::NATIVE_ARRAY . '<' . $this->getStringRepr($type->getKeyType()) . ',' . $this->getStringRepr($type->getElementType()) . '>'; } return sprintf('array<%s,%s,%s>', $this->getStringRepr($type->getKeyType()), $this->getStringRepr($type->getElementType()), $this->dumpJsonLike($itemTypes, true)); case $type instanceof FalseType: return TypeRegistry::NATIVE_BOOLEAN_FALSE; case $type instanceof BooleanType: return TypeRegistry::NATIVE_BOOLEAN; case $type instanceof CallableType: return TypeRegistry::NATIVE_CALLABLE; case $type instanceof ResourceType: return TypeRegistry::NATIVE_RESOURCE; case $type instanceof DoubleType: return TypeRegistry::NATIVE_DOUBLE; case $type instanceof IntegerType: return TypeRegistry::NATIVE_INTEGER; case $type instanceof ThisType: return 'this<' . $type->getReferenceName() . '>'; case $type instanceof NamedType: // If this type has been resolved, we can get the representation // of the resolved type instead of using the reference name. if (!$type->isNoResolvedType()) { return $this->getStringRepr($type->getReferencedType()); } return 'object<' . $type->getReferenceName() . '>'; case $type instanceof NoObjectType: return TypeRegistry::NATIVE_OBJECT; case $type instanceof NoType: return TypeRegistry::NATIVE_NONE; case $type instanceof NullType: return TypeRegistry::NATIVE_NULL; case $type instanceof ObjectType: return 'object<' . $type->getName() . '>'; case $type instanceof StringType: return TypeRegistry::NATIVE_STRING; case $type instanceof UnionType: $alt = array(); foreach ($type->getAlternates() as $t) { $alt[] = $this->getStringRepr($t); } return implode('|', $alt); case $type instanceof UnknownType: return $type->isChecked() ? TypeRegistry::NATIVE_UNKNOWN_CHECKED : TypeRegistry::NATIVE_UNKNOWN; } throw new \InvalidArgumentException(sprintf('The SWITCH statement is exhaustive, but got "%s".', get_class($type))); }
private function isNullableObjectType(PhpType $type) { if (!$type->isUnionType()) { return false; } foreach ($type->getAlternates() as $alt) { if (null === $alt->toMaybeObjectType() && !$alt->isNullType()) { return false; } } return true; }
/** * Returns the array type contained in the given type, or null if no array * type is available. * * @param PhpType|null $type * * @return ArrayType|null */ private function getContainedArrayType(PhpType $type = null) { if (null === $type) { return null; } if ($type->isArrayType()) { return $type; } if (!$type->isUnionType()) { return null; } foreach ($type->getAlternates() as $alt) { if ($alt->isArrayType()) { return $alt; } } return null; }
private function isMoreSpecificType(PhpType $actualType, PhpType $annotatedType) { if ($actualType->equals($annotatedType)) { return false; } if ($actualType->isUnknownType()) { return false; } return $actualType->isSubtypeOf($annotatedType); }