diff --git a/bin/roave-backward-compatibility-check.php b/bin/roave-backward-compatibility-check.php index 27f43ccb..b6242d67 100644 --- a/bin/roave-backward-compatibility-check.php +++ b/bin/roave-backward-compatibility-check.php @@ -114,7 +114,7 @@ static function (string $installationPath) use ($composerIo): Installer { new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\OnlyPublicPropertyChanged( new PropertyBased\MultipleChecksOnAProperty( new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyBecameInternal()), - new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDocumentedTypeChanged()), + new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyTypeChanged(new TypeIsContravariant(), new TypeIsCovariant())), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDefaultValueChanged()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyVisibilityReduced()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyScopeChanged()) @@ -123,7 +123,7 @@ static function (string $installationPath) use ($composerIo): Installer { new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\OnlyProtectedPropertyChanged( new PropertyBased\MultipleChecksOnAProperty( new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyBecameInternal()), - new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDocumentedTypeChanged()), + new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyTypeChanged(new TypeIsContravariant(), new TypeIsCovariant())), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDefaultValueChanged()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyVisibilityReduced()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyScopeChanged()) @@ -193,7 +193,7 @@ static function (string $installationPath) use ($composerIo): Installer { new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\OnlyPublicPropertyChanged( new PropertyBased\MultipleChecksOnAProperty( new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyBecameInternal()), - new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDocumentedTypeChanged()), + new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyTypeChanged(new TypeIsContravariant(), new TypeIsCovariant())), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDefaultValueChanged()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyVisibilityReduced()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyScopeChanged()) @@ -271,7 +271,7 @@ static function (string $installationPath) use ($composerIo): Installer { new ClassBased\SkipClassBasedErrors(new ClassBased\PropertyChanged( new PropertyBased\MultipleChecksOnAProperty( new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyBecameInternal()), - new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDocumentedTypeChanged()), + new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyTypeChanged(new TypeIsContravariant(), new TypeIsCovariant())), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyDefaultValueChanged()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyVisibilityReduced()), new PropertyBased\SkipPropertyBasedErrors(new PropertyBased\PropertyScopeChanged()) diff --git a/src/DetectChanges/BCBreak/ClassBased/MethodRemoved.php b/src/DetectChanges/BCBreak/ClassBased/MethodRemoved.php index 26f31dcb..19e21564 100644 --- a/src/DetectChanges/BCBreak/ClassBased/MethodRemoved.php +++ b/src/DetectChanges/BCBreak/ClassBased/MethodRemoved.php @@ -10,17 +10,17 @@ use Psl\Vec; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; +use Roave\BackwardCompatibility\Formatter\FunctionName; use Roave\BetterReflection\Reflection\ReflectionClass; use Roave\BetterReflection\Reflection\ReflectionMethod; final class MethodRemoved implements ClassBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } public function __invoke(ReflectionClass $fromClass, ReflectionClass $toClass): Changes diff --git a/src/DetectChanges/BCBreak/FunctionBased/ExcludeInternalFunction.php b/src/DetectChanges/BCBreak/FunctionBased/ExcludeInternalFunction.php index 5e7aca5f..c3d11511 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ExcludeInternalFunction.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ExcludeInternalFunction.php @@ -6,7 +6,8 @@ use Psl\Regex; use Roave\BackwardCompatibility\Changes; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; /** * Functions marked "internal" (docblock) are not affected by BC checks. @@ -20,8 +21,10 @@ public function __construct(FunctionBased $check) $this->check = $check; } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { if ($this->isInternalDocComment($fromFunction->getDocComment())) { return Changes::empty(); } diff --git a/src/DetectChanges/BCBreak/FunctionBased/FunctionBased.php b/src/DetectChanges/BCBreak/FunctionBased/FunctionBased.php index 2f41d7e3..ced4e469 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/FunctionBased.php +++ b/src/DetectChanges/BCBreak/FunctionBased/FunctionBased.php @@ -5,9 +5,19 @@ namespace Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased; use Roave\BackwardCompatibility\Changes; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; interface FunctionBased { - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes; + /** + * @template T of ReflectionMethod|ReflectionFunction + * + * @param T $fromFunction + * @param T $toFunction + */ + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes; } diff --git a/src/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternal.php b/src/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternal.php index 38d2feef..dc8d8941 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternal.php +++ b/src/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternal.php @@ -8,23 +8,26 @@ use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; /** * A function that is marked internal is no available to downstream consumers. */ final class FunctionBecameInternal implements FunctionBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { if ( $this->isInternalDocComment($toFunction->getDocComment()) && ! $this->isInternalDocComment($fromFunction->getDocComment()) diff --git a/src/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunction.php b/src/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunction.php index ce30bd80..3753b87e 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunction.php +++ b/src/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunction.php @@ -6,7 +6,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; final class MultipleChecksOnAFunction implements FunctionBased { @@ -18,14 +19,25 @@ public function __construct(FunctionBased ...$checks) $this->checks = $checks; } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { return Changes::fromIterator($this->multipleChecks($fromFunction, $toFunction)); } - /** @return iterable */ - private function multipleChecks(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): iterable - { + /** + * @template T of ReflectionMethod|ReflectionFunction + * + * @param T $fromFunction + * @param T $toFunction + * + * @return iterable + */ + private function multipleChecks( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): iterable { foreach ($this->checks as $check) { yield from $check($fromFunction, $toFunction); } diff --git a/src/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChanged.php index 19b84849..887f2e02 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChanged.php @@ -8,8 +8,9 @@ use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionParameter; /** @@ -19,15 +20,17 @@ */ final class ParameterByReferenceChanged implements FunctionBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { $fromParameters = $fromFunction->getParameters(); $toParameters = $toFunction->getParameters(); $changes = Changes::empty(); diff --git a/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php index aa2a2c84..2dd08ab0 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChanged.php @@ -8,8 +8,9 @@ use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionParameter; use function var_export; @@ -20,15 +21,17 @@ */ final class ParameterDefaultValueChanged implements FunctionBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { $fromParametersWithDefaults = $this->defaultParameterValues($fromFunction); $toParametersWithDefaults = $this->defaultParameterValues($toFunction); @@ -58,7 +61,7 @@ public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFun } /** @return ReflectionParameter[] indexed by parameter index */ - private function defaultParameterValues(ReflectionFunctionAbstract $function): array + private function defaultParameterValues(ReflectionMethod|ReflectionFunction $function): array { return Dict\filter( $function->getParameters(), diff --git a/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeChanged.php index 38d1cef4..daff79f1 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeChanged.php @@ -8,8 +8,9 @@ use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionParameter; use Roave\BetterReflection\Reflection\ReflectionType; @@ -21,15 +22,17 @@ */ final class ParameterTypeChanged implements FunctionBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { return Changes::fromIterator($this->checkSymbols( $fromFunction->getParameters(), $toFunction->getParameters() diff --git a/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChanged.php index b958779f..f82eb6c1 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChanged.php @@ -6,17 +6,14 @@ use Psl\Dict; use Psl\Str; -use Psl\Type; -use ReflectionProperty; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsContravariant; -use Roave\BackwardCompatibility\DetectChanges\Variance\TypeWithReflectorScope; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionParameter; use Roave\BetterReflection\Reflection\ReflectionType; -use Roave\BetterReflection\Reflector\Reflector; /** * When a parameter type changes, the new type should be wider than the previous type, or else @@ -26,16 +23,18 @@ final class ParameterTypeContravarianceChanged implements FunctionBased { private TypeIsContravariant $typeIsContravariant; - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct(TypeIsContravariant $typeIsContravariant) { $this->typeIsContravariant = $typeIsContravariant; - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { $fromParameters = $fromFunction->getParameters(); $toParameters = $toFunction->getParameters(); $changes = Changes::empty(); @@ -52,13 +51,7 @@ private function compareParameter(ReflectionParameter $fromParameter, Reflection $fromType = $fromParameter->getType(); $toType = $toParameter->getType(); - - if ( - ($this->typeIsContravariant)( - new TypeWithReflectorScope($fromType, $this->extractReflector($fromParameter)), - new TypeWithReflectorScope($toType, $this->extractReflector($toParameter)), - ) - ) { + if (($this->typeIsContravariant)($fromType, $toType)) { return Changes::empty(); } @@ -82,15 +75,4 @@ private function typeToString(?ReflectionType $type): string return $type->__toString(); } - - /** @TODO may the gods of BC compliance be merciful on me */ - private function extractReflector(ReflectionParameter $parameter): Reflector - { - $reflectionReflector = new ReflectionProperty(ReflectionFunctionAbstract::class, 'reflector'); - - $reflectionReflector->setAccessible(true); - - return Type\object(Reflector::class) - ->coerce($reflectionReflector->getValue($parameter->getDeclaringFunction())); - } } diff --git a/src/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreased.php b/src/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreased.php index db39a4e0..b4dede6d 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreased.php +++ b/src/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreased.php @@ -7,8 +7,9 @@ use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; /** * When new parameters are added, they must be optional, or else the callers will provide an insufficient @@ -16,15 +17,17 @@ */ final class RequiredParameterAmountIncreased implements FunctionBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { $fromRequiredParameters = $fromFunction->getNumberOfRequiredParameters(); $toRequiredParameters = $toFunction->getNumberOfRequiredParameters(); diff --git a/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChanged.php index b86935ca..7ead9c50 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChanged.php @@ -7,8 +7,9 @@ use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; /** * PHP still (sadly) supports by-ref return types, so the type is wildly different between by-ref and by-val, and @@ -16,15 +17,17 @@ */ final class ReturnTypeByReferenceChanged implements FunctionBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { $fromReturnsReference = $fromFunction->returnsReference(); $toReturnsReference = $toFunction->returnsReference(); diff --git a/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeChanged.php index 7eea221a..d1d95069 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeChanged.php @@ -7,8 +7,9 @@ use Psl\Str; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionType; /** @@ -18,15 +19,17 @@ */ final class ReturnTypeChanged implements FunctionBased { - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct() { - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { $fromReturnType = $this->typeToString($fromFunction->getReturnType()); $toReturnType = $this->typeToString($toFunction->getReturnType()); diff --git a/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChanged.php b/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChanged.php index ad6abb24..c328650c 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChanged.php +++ b/src/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChanged.php @@ -5,16 +5,13 @@ namespace Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased; use Psl\Str; -use Psl\Type; -use ReflectionProperty; use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsCovariant; -use Roave\BackwardCompatibility\DetectChanges\Variance\TypeWithReflectorScope; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BackwardCompatibility\Formatter\FunctionName; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflection\ReflectionType; -use Roave\BetterReflection\Reflector\Reflector; /** * When the return type of a function changes, the new return type must be covariant to the current type. @@ -25,25 +22,22 @@ final class ReturnTypeCovarianceChanged implements FunctionBased { private TypeIsCovariant $typeIsCovariant; - private ReflectionFunctionAbstractName $formatFunction; + private FunctionName $formatFunction; public function __construct(TypeIsCovariant $typeIsCovariant) { $this->typeIsCovariant = $typeIsCovariant; - $this->formatFunction = new ReflectionFunctionAbstractName(); + $this->formatFunction = new FunctionName(); } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { $fromReturnType = $fromFunction->getReturnType(); $toReturnType = $toFunction->getReturnType(); - if ( - ($this->typeIsCovariant)( - new TypeWithReflectorScope($fromReturnType, $this->extractReflector($fromFunction)), - new TypeWithReflectorScope($toReturnType, $this->extractReflector($toFunction)), - ) - ) { + if (($this->typeIsCovariant)($fromReturnType, $toReturnType)) { return Changes::empty(); } @@ -66,15 +60,4 @@ private function typeToString(?ReflectionType $type): string return $type->__toString(); } - - /** @TODO may the gods of BC compliance be merciful on me */ - private function extractReflector(ReflectionFunctionAbstract $function): Reflector - { - $reflectionReflector = new ReflectionProperty(ReflectionFunctionAbstract::class, 'reflector'); - - $reflectionReflector->setAccessible(true); - - return Type\object(Reflector::class) - ->coerce($reflectionReflector->getValue($function)); - } } diff --git a/src/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrors.php b/src/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrors.php index 646788ed..6de411cb 100644 --- a/src/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrors.php +++ b/src/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrors.php @@ -6,7 +6,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\Changes; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Throwable; final class SkipFunctionBasedErrors implements FunctionBased @@ -18,8 +19,10 @@ public function __construct(FunctionBased $next) $this->next = $next; } - public function __invoke(ReflectionFunctionAbstract $fromFunction, ReflectionFunctionAbstract $toFunction): Changes - { + public function __invoke( + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction + ): Changes { try { return ($this->next)($fromFunction, $toFunction); } catch (Throwable $failure) { diff --git a/src/DetectChanges/BCBreak/PropertyBased/PropertyDocumentedTypeChanged.php b/src/DetectChanges/BCBreak/PropertyBased/PropertyDocumentedTypeChanged.php deleted file mode 100644 index 138cc324..00000000 --- a/src/DetectChanges/BCBreak/PropertyBased/PropertyDocumentedTypeChanged.php +++ /dev/null @@ -1,59 +0,0 @@ -formatProperty = new ReflectionPropertyName(); - } - - public function __invoke(ReflectionProperty $fromProperty, ReflectionProperty $toProperty): Changes - { - $toNativeType = []; - $toType = $toProperty->getType(); - if ($toType !== null) { - $toNativeType[] = $toType->getName(); - } - - if ($fromProperty->getDocComment() === '') { - return Changes::empty(); - } - - $fromTypes = Vec\sort($fromProperty->getDocBlockTypeStrings()); - $toTypes = Vec\sort(array_merge($toNativeType, $toProperty->getDocBlockTypeStrings())); - - if ($fromTypes === $toTypes) { - return Changes::empty(); - } - - return Changes::fromList(Change::changed( - Str\format( - 'Type documentation for property %s changed from %s to %s', - ($this->formatProperty)($fromProperty), - Str\join($fromTypes, '|') ?: 'having no type', - Str\join($toTypes, '|') ?: 'having no type' - ), - true - )); - } -} diff --git a/src/DetectChanges/BCBreak/PropertyBased/PropertyTypeChanged.php b/src/DetectChanges/BCBreak/PropertyBased/PropertyTypeChanged.php new file mode 100644 index 00000000..cf0336dd --- /dev/null +++ b/src/DetectChanges/BCBreak/PropertyBased/PropertyTypeChanged.php @@ -0,0 +1,59 @@ +formatProperty = new ReflectionPropertyName(); + } + + public function __invoke(ReflectionProperty $fromProperty, ReflectionProperty $toProperty): Changes + { + $fromType = $fromProperty->getType(); + $toType = $toProperty->getType(); + + if (($this->typeIsCovariant)($fromType, $toType) && ($this->typeIsContravariant)($fromType, $toType)) { + return Changes::empty(); + } + + return Changes::fromList(Change::changed( + Str\format( + 'Type type of property %s changed from %s to %s', + ($this->formatProperty)($fromProperty), + $fromType?->__toString() ?? 'having no type', + $toType?->__toString() ?? 'having no type' + ), + true + )); + } +} diff --git a/src/DetectChanges/Variance/TypeIsContravariant.php b/src/DetectChanges/Variance/TypeIsContravariant.php index 76add1c6..cb62f930 100644 --- a/src/DetectChanges/Variance/TypeIsContravariant.php +++ b/src/DetectChanges/Variance/TypeIsContravariant.php @@ -7,6 +7,7 @@ use Psl\Iter; use Psl\Str; use Roave\BetterReflection\Reflection\ReflectionNamedType; +use Roave\BetterReflection\Reflection\ReflectionType; /** * This is a simplistic contravariant type check. A more appropriate approach would be to @@ -19,12 +20,9 @@ final class TypeIsContravariant { public function __invoke( - TypeWithReflectorScope $originalType, - TypeWithReflectorScope $newType + ?ReflectionType $type, + ?ReflectionType $comparedType ): bool { - $type = $originalType->type; - $comparedType = $newType->type; - if ($comparedType === null) { return true; } @@ -73,13 +71,13 @@ public function __invoke( return false; } - $typeReflectionClass = $originalType->originatingReflector->reflectClass($typeAsString); - $comparedTypeClass = $newType->originatingReflector->reflectClass($comparedTypeAsString); + $typeReflectionClass = $type->getClass(); + $comparedTypeClass = $comparedType->getClass(); if ($comparedTypeClass->isInterface()) { - return $typeReflectionClass->implementsInterface($comparedTypeAsString); + return $typeReflectionClass->implementsInterface($comparedTypeClass->getName()); } - return Iter\contains($typeReflectionClass->getParentClassNames(), $comparedTypeAsString); + return Iter\contains($typeReflectionClass->getParentClassNames(), $comparedTypeClass->getName()); } } diff --git a/src/DetectChanges/Variance/TypeIsCovariant.php b/src/DetectChanges/Variance/TypeIsCovariant.php index c8cc29d2..ef0e9e5c 100644 --- a/src/DetectChanges/Variance/TypeIsCovariant.php +++ b/src/DetectChanges/Variance/TypeIsCovariant.php @@ -7,6 +7,7 @@ use Psl\Iter; use Psl\Str; use Roave\BetterReflection\Reflection\ReflectionNamedType; +use Roave\BetterReflection\Reflection\ReflectionType; use Traversable; /** @@ -20,12 +21,9 @@ final class TypeIsCovariant { public function __invoke( - TypeWithReflectorScope $originalType, - TypeWithReflectorScope $newType + ?ReflectionType $type, + ?ReflectionType $comparedType ): bool { - $type = $originalType->type; - $comparedType = $newType->type; - if ($type === null) { // everything can be covariant to `mixed` return true; @@ -68,7 +66,7 @@ public function __invoke( } if ($typeAsString === 'iterable' && ! $comparedType->isBuiltin()) { - $comparedTypeReflectionClass = $newType->originatingReflector->reflectClass($comparedType->getName()); + $comparedTypeReflectionClass = $comparedType->getClass(); if ($comparedTypeReflectionClass->implementsInterface(Traversable::class)) { // `iterable` can be restricted via any `Iterator` implementation @@ -86,13 +84,16 @@ public function __invoke( return false; } - $originalTypeReflectionClass = $originalType->originatingReflector->reflectClass($typeAsString); - $comparedTypeReflectionClass = $newType->originatingReflector->reflectClass($comparedTypeAsString); + $originalTypeReflectionClass = $type->getClass(); + $comparedTypeReflectionClass = $comparedType->getClass(); if ($originalTypeReflectionClass->isInterface()) { - return $comparedTypeReflectionClass->implementsInterface($typeAsString); + return $comparedTypeReflectionClass->implementsInterface($originalTypeReflectionClass->getName()); } - return Iter\contains($comparedTypeReflectionClass->getParentClassNames(), $typeAsString); + return Iter\contains( + $comparedTypeReflectionClass->getParentClassNames(), + $originalTypeReflectionClass->getName() + ); } } diff --git a/src/DetectChanges/Variance/TypeWithReflectorScope.php b/src/DetectChanges/Variance/TypeWithReflectorScope.php deleted file mode 100644 index 6694deb1..00000000 --- a/src/DetectChanges/Variance/TypeWithReflectorScope.php +++ /dev/null @@ -1,28 +0,0 @@ -isStatic()) { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternalTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternalTest.php index 877d4e85..f9775dd7 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternalTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/FunctionBecameInternalTest.php @@ -8,7 +8,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\FunctionBecameInternal; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; @@ -26,8 +27,8 @@ final class FunctionBecameInternalTest extends TestCase * @dataProvider functionsToBeTested */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ): void { $changes = (new FunctionBecameInternal())($fromFunction, $toFunction); @@ -41,8 +42,11 @@ public function testDiffs( } /** - * @return array>> - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested(): array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunctionTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunctionTest.php index 04796119..6cf60e0a 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunctionTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/MultipleChecksOnAFunctionTest.php @@ -9,7 +9,7 @@ use Roave\BackwardCompatibility\Changes; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\FunctionBased; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\MultipleChecksOnAFunction; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; use RoaveTest\BackwardCompatibility\Assertion; /** @@ -25,8 +25,8 @@ public function testChecksAllGivenCheckers(): void $multiCheck = new MultipleChecksOnAFunction($checker1, $checker2, $checker3); - $from = $this->createMock(ReflectionFunctionAbstract::class); - $to = $this->createMock(ReflectionFunctionAbstract::class); + $from = $this->createMock(ReflectionFunction::class); + $to = $this->createMock(ReflectionFunction::class); $checker1 ->expects(self::once()) diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChangedTest.php index 1221ac1f..c40172a3 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterByReferenceChangedTest.php @@ -8,7 +8,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\ParameterByReferenceChanged; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -26,8 +27,8 @@ final class ParameterByReferenceChangedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new ParameterByReferenceChanged())($fromFunction, $toFunction); @@ -41,9 +42,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php index 2fb125b0..42b60d40 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterDefaultValueChangedTest.php @@ -8,7 +8,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\ParameterDefaultValueChanged; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -26,8 +27,8 @@ final class ParameterDefaultValueChangedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new ParameterDefaultValueChanged())($fromFunction, $toFunction); @@ -41,9 +42,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeChangedTest.php index c9de0ff1..674741b2 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeChangedTest.php @@ -8,7 +8,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\ParameterTypeChanged; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -26,8 +27,8 @@ final class ParameterTypeChangedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new ParameterTypeChanged())($fromFunction, $toFunction); @@ -41,9 +42,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChangedTest.php index 5cfe6a4d..c2ab8f6e 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ParameterTypeContravarianceChangedTest.php @@ -9,7 +9,8 @@ use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\ParameterTypeContravarianceChanged; use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsContravariant; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -27,8 +28,8 @@ final class ParameterTypeContravarianceChangedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new ParameterTypeContravarianceChanged(new TypeIsContravariant()))($fromFunction, $toFunction); @@ -42,9 +43,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreasedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreasedTest.php index b3d556c1..3b896c83 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreasedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/RequiredParameterAmountIncreasedTest.php @@ -8,7 +8,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\RequiredParameterAmountIncreased; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -26,8 +27,8 @@ final class RequiredParameterAmountIncreasedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new RequiredParameterAmountIncreased())($fromFunction, $toFunction); @@ -41,9 +42,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChangedTest.php index c5e67d12..7f251006 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeByReferenceChangedTest.php @@ -8,7 +8,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\ReturnTypeByReferenceChanged; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -26,8 +27,8 @@ final class ReturnTypeByReferenceChangedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new ReturnTypeByReferenceChanged())($fromFunction, $toFunction); @@ -41,9 +42,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeChangedTest.php index 2c3c6a89..75c6b9c4 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeChangedTest.php @@ -8,7 +8,8 @@ use Roave\BackwardCompatibility\Change; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\ReturnTypeChanged; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -26,8 +27,8 @@ final class ReturnTypeChangedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new ReturnTypeChanged())($fromFunction, $toFunction); @@ -41,9 +42,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChangedTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChangedTest.php index 49b253ef..51989efc 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/ReturnTypeCovarianceChangedTest.php @@ -9,7 +9,8 @@ use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\ReturnTypeCovarianceChanged; use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsCovariant; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_combine; @@ -27,8 +28,8 @@ final class ReturnTypeCovarianceChangedTest extends TestCase * @param string[] $expectedMessages */ public function testDiffs( - ReflectionFunctionAbstract $fromFunction, - ReflectionFunctionAbstract $toFunction, + ReflectionMethod|ReflectionFunction $fromFunction, + ReflectionMethod|ReflectionFunction $toFunction, array $expectedMessages ) : void { $changes = (new ReturnTypeCovarianceChanged(new TypeIsCovariant()))($fromFunction, $toFunction); @@ -42,9 +43,11 @@ public function testDiffs( } /** - * @return array>> - * - * @psalm-return array}> + * @return array + * }> */ public function functionsToBeTested() : array { diff --git a/test/unit/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrorsTest.php b/test/unit/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrorsTest.php index 4a3a7564..b42656d4 100644 --- a/test/unit/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrorsTest.php +++ b/test/unit/DetectChanges/BCBreak/FunctionBased/SkipFunctionBasedErrorsTest.php @@ -11,8 +11,8 @@ use Roave\BackwardCompatibility\Changes; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\FunctionBased; use Roave\BackwardCompatibility\DetectChanges\BCBreak\FunctionBased\SkipFunctionBasedErrors; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; use function uniqid; /** @@ -33,8 +33,8 @@ protected function setUp(): void public function testWillForwardChecks(): void { - $fromFunction = $this->createMock(ReflectionFunctionAbstract::class); - $toFunction = $this->createMock(ReflectionFunctionAbstract::class); + $fromFunction = $this->createMock(ReflectionFunction::class); + $toFunction = $this->createMock(ReflectionFunction::class); $expectedChanges = Changes::fromList(Change::added( uniqid('foo', true), true @@ -52,8 +52,8 @@ public function testWillForwardChecks(): void public function testWillCollectFailures(): void { - $fromFunction = $this->createMock(ReflectionFunctionAbstract::class); - $toFunction = $this->createMock(ReflectionFunctionAbstract::class); + $fromFunction = $this->createMock(ReflectionFunction::class); + $toFunction = $this->createMock(ReflectionFunction::class); $exception = new Exception(); $this diff --git a/test/unit/DetectChanges/BCBreak/PropertyBased/PropertyDocumentedTypeChangedTest.php b/test/unit/DetectChanges/BCBreak/PropertyBased/PropertyTypeChangedTest.php similarity index 81% rename from test/unit/DetectChanges/BCBreak/PropertyBased/PropertyDocumentedTypeChangedTest.php rename to test/unit/DetectChanges/BCBreak/PropertyBased/PropertyTypeChangedTest.php index 3d0d0677..a2ea72c1 100644 --- a/test/unit/DetectChanges/BCBreak/PropertyBased/PropertyDocumentedTypeChangedTest.php +++ b/test/unit/DetectChanges/BCBreak/PropertyBased/PropertyTypeChangedTest.php @@ -6,7 +6,9 @@ use PHPUnit\Framework\TestCase; use Roave\BackwardCompatibility\Change; -use Roave\BackwardCompatibility\DetectChanges\BCBreak\PropertyBased\PropertyDocumentedTypeChanged; +use Roave\BackwardCompatibility\DetectChanges\BCBreak\PropertyBased\PropertyTypeChanged; +use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsContravariant; +use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsCovariant; use Roave\BetterReflection\BetterReflection; use Roave\BetterReflection\Reflection\ReflectionProperty; use Roave\BetterReflection\Reflector\DefaultReflector; @@ -19,9 +21,9 @@ use function iterator_to_array; /** - * @covers \Roave\BackwardCompatibility\DetectChanges\BCBreak\PropertyBased\PropertyDocumentedTypeChanged + * @covers \Roave\BackwardCompatibility\DetectChanges\BCBreak\PropertyBased\PropertyTypeChanged */ -final class PropertyDocumentedTypeChangedTest extends TestCase +final class PropertyTypeChangedTest extends TestCase { /** * @param string[] $expectedMessages @@ -33,7 +35,10 @@ public function testDiffs( ReflectionProperty $toProperty, array $expectedMessages ): void { - $changes = (new PropertyDocumentedTypeChanged())($fromProperty, $toProperty); + $changes = (new PropertyTypeChanged( + new TypeIsContravariant(), + new TypeIsCovariant() + ))($fromProperty, $toProperty); self::assertSame( $expectedMessages, @@ -123,6 +128,8 @@ class TheClass { * @var int */ public $propertyWithDocblockTypeHintChangeToNativeTypeHintAndTypeChange; + + public int $propertyWithDeclaredTypeRemoved; } PHP , @@ -196,6 +203,8 @@ class TheClass { public int $propertyWithDocblockTypeHintChangeToNativeTypeHint; public float $propertyWithDocblockTypeHintChangeToNativeTypeHintAndTypeChange; + + public $propertyWithDeclaredTypeRemoved; } PHP , @@ -207,22 +216,27 @@ class TheClass { $fromClass = $fromClassReflector->reflectClass('TheClass'); $toClass = $toClassReflector->reflectClass('TheClass'); + // Note: lots of docblock-related tests report no BC breaks here. This is because this change checker does + // not operate on documented types anymore. Documented types are too advanced for this library to inspect, + // right now, since psalm/phpstan/psr-5 are constantly evolving. The library will limit itself in + // inspecting reflection-based type changes (for now). $properties = [ 'publicNoDocblockToNoDocblock' => [], 'publicNoDocblockToDocblock' => [], - 'publicNoTypeDocblockToDocblock' => ['[BC] CHANGED: Type documentation for property TheClass#$publicNoTypeDocblockToDocblock changed from having no type to int'], + 'publicNoTypeDocblockToDocblock' => [], 'publicDocblockToSameDocblock' => [], - 'publicDocblockToDifferentDocblock' => ['[BC] CHANGED: Type documentation for property TheClass#$publicDocblockToDifferentDocblock changed from int to float'], - 'publicDocblockToNoDocblock' => ['[BC] CHANGED: Type documentation for property TheClass#$publicDocblockToNoDocblock changed from int to having no type'], + 'publicDocblockToDifferentDocblock' => [], + 'publicDocblockToNoDocblock' => [], 'publicCompositeTypeDocblockToSameTypeDocblock' => [], 'publicCompositeTypeDocblockToSameTypeDocblockWithDifferentSorting' => [], - 'publicCompositeTypeDocblockToDifferentCompositeTypeDocblock' => ['[BC] CHANGED: Type documentation for property TheClass#$publicCompositeTypeDocblockToDifferentCompositeTypeDocblock changed from float|int to float|int|string'], - 'privateDocblockToDifferentDocblock' => ['[BC] CHANGED: Type documentation for property TheClass#$privateDocblockToDifferentDocblock changed from int to float'], + 'publicCompositeTypeDocblockToDifferentCompositeTypeDocblock' => [], + 'privateDocblockToDifferentDocblock' => [], 'duplicatePropertyTypesBeingDeduplicatedAreNotBcBreaks' => [], 'propertyTypeBeingDuplicatedAreNotBcBreaks' => [], 'propertyWithComplexDocblockThatCannotBeParsed' => [], - 'propertyWithDocblockTypeHintChangeToNativeTypeHint' => [], - 'propertyWithDocblockTypeHintChangeToNativeTypeHintAndTypeChange' => ['[BC] CHANGED: Type documentation for property TheClass#$propertyWithDocblockTypeHintChangeToNativeTypeHintAndTypeChange changed from int to float'], + 'propertyWithDocblockTypeHintChangeToNativeTypeHint' => ['[BC] CHANGED: Type type of property TheClass#$propertyWithDocblockTypeHintChangeToNativeTypeHint changed from having no type to int'], + 'propertyWithDocblockTypeHintChangeToNativeTypeHintAndTypeChange' => ['[BC] CHANGED: Type type of property TheClass#$propertyWithDocblockTypeHintChangeToNativeTypeHintAndTypeChange changed from having no type to float'], + 'propertyWithDeclaredTypeRemoved' => ['[BC] CHANGED: Type type of property TheClass#$propertyWithDeclaredTypeRemoved changed from int to having no type'], ]; return array_combine( diff --git a/test/unit/DetectChanges/Variance/TypeIsContravariantTest.php b/test/unit/DetectChanges/Variance/TypeIsContravariantTest.php index 2cbbb811..0c8473db 100644 --- a/test/unit/DetectChanges/Variance/TypeIsContravariantTest.php +++ b/test/unit/DetectChanges/Variance/TypeIsContravariantTest.php @@ -7,11 +7,14 @@ use PhpParser\Node\Identifier; use PhpParser\Node\NullableType; use PHPUnit\Framework\TestCase; +use Psl\Type; use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsContravariant; use Roave\BackwardCompatibility\DetectChanges\Variance\TypeWithReflectorScope; use Roave\BetterReflection\BetterReflection; +use Roave\BetterReflection\Reflection\ReflectionProperty; use Roave\BetterReflection\Reflection\ReflectionType; use Roave\BetterReflection\Reflector\DefaultReflector; +use Roave\BetterReflection\Reflector\Reflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_map; @@ -23,8 +26,8 @@ final class TypeIsContravariantTest extends TestCase * @dataProvider checkedTypes */ public function testContravariance( - TypeWithReflectorScope $type, - TypeWithReflectorScope $newType, + ?ReflectionType $type, + ?ReflectionType $newType, bool $expectedToBeContravariant ): void { self::assertSame( @@ -34,8 +37,11 @@ public function testContravariance( } /** - * @return array> - * @psalm-return array + * @return array */ public function checkedTypes(): array { @@ -52,11 +58,18 @@ class AnotherClassWithMultipleInterfaces implements AnInterface, AnotherInterfac class AClass {} class BClass extends AClass {} class CClass extends BClass {} +final class OwnerPropertyContainer { private $owner; } PHP , (new BetterReflection())->astLocator() )); + $owner = Type\object(ReflectionProperty::class) + ->coerce( + $reflector->reflectClass('OwnerPropertyContainer') + ->getProperty('owner') + ); + $types = [ 'no type to no type is contravariant with itself' => [ null, @@ -65,150 +78,154 @@ class CClass extends BClass {} ], 'no type to void type is not contravariant' => [ null, - ReflectionType::createFromNode(new Identifier('void')), + new Identifier('void'), false, ], 'void type to no type is contravariant' => [ - ReflectionType::createFromNode(new Identifier('void')), + new Identifier('void'), null, true, ], 'void type to scalar type is contravariant' => [ - ReflectionType::createFromNode(new Identifier('void')), - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('void'), + new Identifier('string'), true, ], 'void type to class type is contravariant' => [ - ReflectionType::createFromNode(new Identifier('void')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('void'), + new Identifier('AClass'), true, ], 'scalar type to no type is contravariant' => [ - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('string'), null, true, ], 'no type to scalar type is not contravariant' => [ null, - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('string'), false, ], 'class type to no type is contravariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('AClass'), null, true, ], 'no type to class type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('AClass'), null, true, ], 'iterable to array is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('array')), + new Identifier('iterable'), + new Identifier('array'), false, ], 'array to iterable is contravariant' => [ - ReflectionType::createFromNode(new Identifier('array')), - ReflectionType::createFromNode(new Identifier('iterable')), + new Identifier('array'), + new Identifier('iterable'), true, ], 'iterable to non-iterable class type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), + new Identifier('iterable'), + new Identifier('AnotherClassWithMultipleInterfaces'), false, ], 'iterable to iterable class type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('Iterator')), + new Identifier('iterable'), + new Identifier('Iterator'), false, ], 'non-iterable class to iterable type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), + new Identifier('iterable'), + new Identifier('AnotherClassWithMultipleInterfaces'), false, ], 'iterable class type to iterable is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('Iterator')), - ReflectionType::createFromNode(new Identifier('iterable')), + new Identifier('Iterator'), + new Identifier('iterable'), false, ], 'object to class type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('object')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('object'), + new Identifier('AClass'), false, ], 'class type to object is contravariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), - ReflectionType::createFromNode(new Identifier('object')), + new Identifier('AClass'), + new Identifier('object'), true, ], 'class type to scalar type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('AClass'), + new Identifier('string'), false, ], 'scalar type to class type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('string')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('string'), + new Identifier('AClass'), false, ], 'scalar type (string) to different scalar type (int) is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('string')), - ReflectionType::createFromNode(new Identifier('int')), + new Identifier('string'), + new Identifier('int'), false, ], 'scalar type (int) to different scalar type (float) is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('int')), - ReflectionType::createFromNode(new Identifier('float')), + new Identifier('int'), + new Identifier('float'), false, ], 'object type to scalar type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('object')), - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('object'), + new Identifier('string'), false, ], 'scalar type to object type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('string')), - ReflectionType::createFromNode(new Identifier('object')), + new Identifier('string'), + new Identifier('object'), false, ], 'class to superclass is contravariant' => [ - ReflectionType::createFromNode(new Identifier('BClass')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('BClass'), + new Identifier('AClass'), true, ], 'class to subclass is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('BClass')), - ReflectionType::createFromNode(new Identifier('CClass')), + new Identifier('BClass'), + new Identifier('CClass'), false, ], 'class to implemented interface is contravariant' => [ - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), - ReflectionType::createFromNode(new Identifier('AnInterface')), + new Identifier('AnotherClassWithMultipleInterfaces'), + new Identifier('AnInterface'), true, ], 'class to not implemented interface is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), - ReflectionType::createFromNode(new Identifier('Traversable')), + new Identifier('AnotherClassWithMultipleInterfaces'), + new Identifier('Traversable'), false, ], 'interface to parent interface is contravariant' => [ - ReflectionType::createFromNode(new Identifier('Iterator')), - ReflectionType::createFromNode(new Identifier('Traversable')), + new Identifier('Iterator'), + new Identifier('Traversable'), true, ], 'interface to child interface is contravariant' => [ - ReflectionType::createFromNode(new Identifier('Traversable')), - ReflectionType::createFromNode(new Identifier('Iterator')), + new Identifier('Traversable'), + new Identifier('Iterator'), false, ], ]; return array_map( static fn (array $types): array => [ - new TypeWithReflectorScope($types[0], $reflector), - new TypeWithReflectorScope($types[1], $reflector), + $types[0] === null + ? null + : self::identifierType($reflector, $owner, $types[0]), + $types[1] === null + ? null + : self::identifierType($reflector, $owner, $types[1]), $types[2], ], $types @@ -218,14 +235,14 @@ class CClass extends BClass {} /** * @dataProvider existingTypes */ - public function testContravarianceConsidersSameTypeAlwaysContravariant(TypeWithReflectorScope $type): void + public function testContravarianceConsidersSameTypeAlwaysContravariant(?ReflectionType $type): void { self::assertTrue( (new TypeIsContravariant())($type, $type) ); } - /** @return TypeWithReflectorScope[][] */ + /** @return list */ public function existingTypes(): array { $reflector = new DefaultReflector(new StringSourceLocator( @@ -234,20 +251,25 @@ public function existingTypes(): array interface Traversable {} class AClass {} +final class OwnerPropertyContainer { private $owner; } PHP , (new BetterReflection())->astLocator() )); + $owner = Type\object(ReflectionProperty::class) + ->coerce( + $reflector->reflectClass('OwnerPropertyContainer') + ->getProperty('owner') + ); + return array_merge( - [[new TypeWithReflectorScope(null, $reflector)]], + [[null]], array_merge(...array_map( - static function (string $type) use ($reflector): array { - return [ - [new TypeWithReflectorScope(ReflectionType::createFromNode(new Identifier($type)), $reflector)], - [new TypeWithReflectorScope(ReflectionType::createFromNode(new NullableType(new Identifier($type))), $reflector)], - ]; - }, + static fn (string $type): array => [ + [self::identifierType($reflector, $owner, new Identifier($type))], + [self::identifierType($reflector, $owner, new NullableType(new Identifier($type)))], + ], [ 'int', 'string', @@ -274,12 +296,20 @@ public function testContravarianceConsidersNullability(string $type): void interface Traversable {} class AClass {} +final class OwnerPropertyContainer { private $owner; } PHP , (new BetterReflection())->astLocator() )); - $nullable = new TypeWithReflectorScope(ReflectionType::createFromNode(new NullableType(new Identifier($type))), $reflector); - $notNullable = new TypeWithReflectorScope(ReflectionType::createFromNode(new Identifier($type)), $reflector); + + $owner = Type\object(ReflectionProperty::class) + ->coerce( + $reflector->reflectClass('OwnerPropertyContainer') + ->getProperty('owner') + ); + + $nullable = self::identifierType($reflector, $owner, new NullableType(new Identifier($type))); + $notNullable = self::identifierType($reflector, $owner, new Identifier($type)); $isContravariant = new TypeIsContravariant(); @@ -302,4 +332,12 @@ public function existingNullableTypeStrings(): array ['AClass'], ]; } + + private static function identifierType( + Reflector $reflector, + ReflectionProperty $owner, + Identifier|NullableType $identifier + ): ReflectionType { + return ReflectionType::createFromNode($reflector, $owner, $identifier); + } } diff --git a/test/unit/DetectChanges/Variance/TypeIsCovariantTest.php b/test/unit/DetectChanges/Variance/TypeIsCovariantTest.php index 50f35c1c..73418cf1 100644 --- a/test/unit/DetectChanges/Variance/TypeIsCovariantTest.php +++ b/test/unit/DetectChanges/Variance/TypeIsCovariantTest.php @@ -7,11 +7,13 @@ use PhpParser\Node\Identifier; use PhpParser\Node\NullableType; use PHPUnit\Framework\TestCase; +use Psl\Type; use Roave\BackwardCompatibility\DetectChanges\Variance\TypeIsCovariant; -use Roave\BackwardCompatibility\DetectChanges\Variance\TypeWithReflectorScope; use Roave\BetterReflection\BetterReflection; +use Roave\BetterReflection\Reflection\ReflectionProperty; use Roave\BetterReflection\Reflection\ReflectionType; use Roave\BetterReflection\Reflector\DefaultReflector; +use Roave\BetterReflection\Reflector\Reflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; use function array_map; @@ -23,8 +25,8 @@ final class TypeIsCovariantTest extends TestCase * @dataProvider checkedTypes */ public function testCovariance( - TypeWithReflectorScope $type, - TypeWithReflectorScope $newType, + ?ReflectionType $type, + ?ReflectionType $newType, bool $expectedToBeContravariant ): void { self::assertSame( @@ -34,8 +36,11 @@ public function testCovariance( } /** - * @return array> - * @psalm-return array + * @return array */ public function checkedTypes(): array { @@ -52,174 +57,185 @@ class AnotherClassWithMultipleInterfaces implements AnInterface, AnotherInterfac class AClass {} class BClass extends AClass {} class CClass extends BClass {} +final class OwnerPropertyContainer { private $owner; } PHP , (new BetterReflection())->astLocator() )); + $owner = Type\object(ReflectionProperty::class) + ->coerce( + $reflector->reflectClass('OwnerPropertyContainer') + ->getProperty('owner') + ); + $types = [ 'no type to void type is covariant' => [ null, - ReflectionType::createFromNode(new Identifier('void')), + new Identifier('void'), true, ], 'void type to no type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('void')), + new Identifier('void'), null, false, ], 'void type to scalar type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('void')), - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('void'), + new Identifier('string'), false, ], 'void type to class type is covariant' => [ - ReflectionType::createFromNode(new Identifier('void')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('void'), + new Identifier('AClass'), false, ], 'scalar type to no type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('string'), null, false, ], 'no type to scalar type is covariant' => [ null, - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('string'), true, ], 'class type to no type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('AClass'), null, false, ], 'no type to class type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('AClass'), null, false, ], 'iterable to array is covariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('array')), + new Identifier('iterable'), + new Identifier('array'), true, ], 'iterable to scalar is not covariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('int')), + new Identifier('iterable'), + new Identifier('int'), false, ], 'scalar to iterable is not covariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('int')), + new Identifier('iterable'), + new Identifier('int'), false, ], 'array to iterable is not covariant' => [ - ReflectionType::createFromNode(new Identifier('array')), - ReflectionType::createFromNode(new Identifier('iterable')), + new Identifier('array'), + new Identifier('iterable'), false, ], 'iterable to non-iterable class type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), + new Identifier('iterable'), + new Identifier('AnotherClassWithMultipleInterfaces'), false, ], 'iterable to iterable class type is covariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('Iterator')), + new Identifier('iterable'), + new Identifier('Iterator'), true, ], 'non-iterable class to iterable type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('iterable')), - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), + new Identifier('iterable'), + new Identifier('AnotherClassWithMultipleInterfaces'), false, ], 'iterable class type to iterable is not covariant' => [ - ReflectionType::createFromNode(new Identifier('Iterator')), - ReflectionType::createFromNode(new Identifier('iterable')), + new Identifier('Iterator'), + new Identifier('iterable'), false, ], 'object to class type is covariant' => [ - ReflectionType::createFromNode(new Identifier('object')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('object'), + new Identifier('AClass'), true, ], 'class type to object is not covariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), - ReflectionType::createFromNode(new Identifier('object')), + new Identifier('AClass'), + new Identifier('object'), false, ], 'class type to scalar type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('AClass')), - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('AClass'), + new Identifier('string'), false, ], 'scalar type to class type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('string')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('string'), + new Identifier('AClass'), false, ], 'scalar type (string) to different scalar type (int) is not covariant' => [ - ReflectionType::createFromNode(new Identifier('string')), - ReflectionType::createFromNode(new Identifier('int')), + new Identifier('string'), + new Identifier('int'), false, ], 'scalar type (int) to different scalar type (float) is not covariant' => [ - ReflectionType::createFromNode(new Identifier('int')), - ReflectionType::createFromNode(new Identifier('float')), + new Identifier('int'), + new Identifier('float'), false, ], 'object type to scalar type is not contravariant' => [ - ReflectionType::createFromNode(new Identifier('object')), - ReflectionType::createFromNode(new Identifier('string')), + new Identifier('object'), + new Identifier('string'), false, ], 'scalar type to object type is not covariant' => [ - ReflectionType::createFromNode(new Identifier('string')), - ReflectionType::createFromNode(new Identifier('object')), + new Identifier('string'), + new Identifier('object'), false, ], 'class to superclass is not covariant' => [ - ReflectionType::createFromNode(new Identifier('BClass')), - ReflectionType::createFromNode(new Identifier('AClass')), + new Identifier('BClass'), + new Identifier('AClass'), false, ], 'class to subclass is covariant' => [ - ReflectionType::createFromNode(new Identifier('BClass')), - ReflectionType::createFromNode(new Identifier('CClass')), + new Identifier('BClass'), + new Identifier('CClass'), true, ], 'class to implemented interface is not covariant' => [ - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), - ReflectionType::createFromNode(new Identifier('AnInterface')), + new Identifier('AnotherClassWithMultipleInterfaces'), + new Identifier('AnInterface'), false, ], 'interface to implementing class is covariant' => [ - ReflectionType::createFromNode(new Identifier('AnInterface')), - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), + new Identifier('AnInterface'), + new Identifier('AnotherClassWithMultipleInterfaces'), true, ], 'class to not implemented interface is not covariant' => [ - ReflectionType::createFromNode(new Identifier('AnotherClassWithMultipleInterfaces')), - ReflectionType::createFromNode(new Identifier('Traversable')), + new Identifier('AnotherClassWithMultipleInterfaces'), + new Identifier('Traversable'), false, ], 'interface to parent interface is not covariant' => [ - ReflectionType::createFromNode(new Identifier('Iterator')), - ReflectionType::createFromNode(new Identifier('Traversable')), + new Identifier('Iterator'), + new Identifier('Traversable'), false, ], 'interface to child interface is covariant' => [ - ReflectionType::createFromNode(new Identifier('Traversable')), - ReflectionType::createFromNode(new Identifier('Iterator')), + new Identifier('Traversable'), + new Identifier('Iterator'), true, ], ]; return array_map( static fn (array $types): array => [ - new TypeWithReflectorScope($types[0], $reflector), - new TypeWithReflectorScope($types[1], $reflector), + $types[0] === null + ? null + : self::identifierType($reflector, $owner, $types[0]), + $types[1] === null + ? null + : self::identifierType($reflector, $owner, $types[1]), $types[2], ], $types @@ -229,14 +245,16 @@ class CClass extends BClass {} /** * @dataProvider existingTypes */ - public function testCovarianceConsidersSameTypeAlwaysCovariant(TypeWithReflectorScope $type): void + public function testCovarianceConsidersSameTypeAlwaysCovariant(?ReflectionType $type): void { self::assertTrue( (new TypeIsCovariant())($type, $type) ); } - /** @return TypeWithReflectorScope[][] */ + /** + * @return list + */ public function existingTypes(): array { $reflector = new DefaultReflector(new StringSourceLocator( @@ -245,20 +263,25 @@ public function existingTypes(): array interface Traversable {} class AClass {} +final class OwnerPropertyContainer { private $owner; } PHP , (new BetterReflection())->astLocator() )); + $owner = Type\object(ReflectionProperty::class) + ->coerce( + $reflector->reflectClass('OwnerPropertyContainer') + ->getProperty('owner') + ); + return array_merge( - [[new TypeWithReflectorScope(null, $reflector)]], + [[null]], array_merge(...array_map( - static function (string $type) use ($reflector): array { - return [ - [new TypeWithReflectorScope(ReflectionType::createFromNode(new Identifier($type)), $reflector)], - [new TypeWithReflectorScope(ReflectionType::createFromNode(new NullableType(new Identifier($type))), $reflector)], - ]; - }, + static fn (string $type): array => [ + [self::identifierType($reflector, $owner, new Identifier($type))], + [self::identifierType($reflector, $owner, new NullableType(new Identifier($type)))], + ], [ 'int', 'string', @@ -285,12 +308,20 @@ public function testCovarianceConsidersNullability(string $type): void interface Traversable {} class AClass {} +final class OwnerPropertyContainer { private $owner; } PHP , (new BetterReflection())->astLocator() )); - $nullable = new TypeWithReflectorScope(ReflectionType::createFromNode(new NullableType(new Identifier($type))), $reflector); - $notNullable = new TypeWithReflectorScope(ReflectionType::createFromNode(new Identifier($type)), $reflector); + + $owner = Type\object(ReflectionProperty::class) + ->coerce( + $reflector->reflectClass('OwnerPropertyContainer') + ->getProperty('owner') + ); + + $nullable = self::identifierType($reflector, $owner, new NullableType(new Identifier($type))); + $notNullable = self::identifierType($reflector, $owner, new Identifier($type)); $isCovariant = new TypeIsCovariant(); @@ -313,4 +344,12 @@ public function existingNullableTypeStrings(): array ['AClass'], ]; } + + private static function identifierType( + Reflector $reflector, + ReflectionProperty $owner, + Identifier|NullableType $identifier + ): ReflectionType { + return ReflectionType::createFromNode($reflector, $owner, $identifier); + } } diff --git a/test/unit/Formatter/ReflectionFunctionAbstractNameTest.php b/test/unit/Formatter/ReflectionFunctionAbstractNameTest.php index 7cefb9c6..1b4e907a 100644 --- a/test/unit/Formatter/ReflectionFunctionAbstractNameTest.php +++ b/test/unit/Formatter/ReflectionFunctionAbstractNameTest.php @@ -5,29 +5,31 @@ namespace RoaveTest\BackwardCompatibility\Formatter; use PHPUnit\Framework\TestCase; -use Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName; +use Roave\BackwardCompatibility\Formatter\FunctionName; use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionFunctionAbstract; +use Roave\BetterReflection\Reflection\ReflectionFunction; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\DefaultReflector; use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator; /** - * @covers \Roave\BackwardCompatibility\Formatter\ReflectionFunctionAbstractName + * @covers \Roave\BackwardCompatibility\Formatter\FunctionName */ final class ReflectionFunctionAbstractNameTest extends TestCase { /** * @dataProvider functionsToBeTested */ - public function testName(ReflectionFunctionAbstract $function, string $expectedName) : void + public function testName(ReflectionFunction|ReflectionMethod $function, string $expectedName) : void { - self::assertSame($expectedName, (new ReflectionFunctionAbstractName())($function)); + self::assertSame($expectedName, (new FunctionName())($function)); } /** - * @return array> - * - * @psalm-return array + * @return array */ public function functionsToBeTested() : array {