diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php index 6492f471120..42baa488114 100644 --- a/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php +++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php @@ -37,7 +37,11 @@ final class ClosureTypeMapper implements TypeMapperInterface { $identifierTypeNode = new IdentifierTypeNode($type->getClassName()); $returnDocTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getReturnType(), $typeKind); - return new SpacingAwareCallableTypeNode($identifierTypeNode, [], $returnDocTypeNode); + $parameterDocTypeNodes = []; + foreach ($type->getParameters() as $parameterReflection) { + $parameterDocTypeNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($parameterReflection->getType(), $typeKind); + } + return new SpacingAwareCallableTypeNode($identifierTypeNode, $parameterDocTypeNodes, $returnDocTypeNode); } /** * @param TypeKind::* $typeKind diff --git a/rules/TypeDeclaration/Helper/PhpDocNullableTypeHelper.php b/rules/TypeDeclaration/Helper/PhpDocNullableTypeHelper.php index c6a4ab9ebb5..dd2d10c59f4 100644 --- a/rules/TypeDeclaration/Helper/PhpDocNullableTypeHelper.php +++ b/rules/TypeDeclaration/Helper/PhpDocNullableTypeHelper.php @@ -5,6 +5,7 @@ namespace Rector\TypeDeclaration\Helper; use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Param; +use PHPStan\Type\ClosureType; use PHPStan\Type\MixedType; use PHPStan\Type\NullType; use PHPStan\Type\Type; @@ -72,6 +73,63 @@ final class PhpDocNullableTypeHelper } return $cleanNullableMixed; } + /** + * @param array $updatedDocTypes + * + * @return array + */ + private function appendOrPrependNullTypeIfAppropriate(bool $isPhpParserTypeContainingNullType, bool $isPhpDocTypeContainingClosureType, array $updatedDocTypes) : array + { + if (!$isPhpParserTypeContainingNullType) { + return $updatedDocTypes; + } + if ($isPhpDocTypeContainingClosureType) { + \array_unshift($updatedDocTypes, new NullType()); + } else { + $updatedDocTypes[] = new NullType(); + } + return $updatedDocTypes; + } + private function hasClosureType(Type $phpDocType) : bool + { + if ($phpDocType instanceof ClosureType) { + return \true; + } + if ($phpDocType instanceof UnionType) { + foreach ($phpDocType->getTypes() as $subType) { + if ($subType instanceof ClosureType) { + return \true; + } + } + } + return \false; + } + private function hasNullType(Type $phpDocType) : bool + { + $isPhpDocTypeContainingNullType = \false; + if ($phpDocType instanceof UnionType) { + return TypeCombinator::containsNull($phpDocType); + } + return $isPhpDocTypeContainingNullType; + } + /** + * @return Type[] + */ + private function resolveUpdatedDocTypes(Type $phpDocType) : array + { + $updatedDocTypes = []; + if ($phpDocType instanceof UnionType) { + foreach ($phpDocType->getTypes() as $subType) { + if ($subType instanceof NullType) { + continue; + } + $updatedDocTypes[] = $subType; + } + } else { + $updatedDocTypes[] = $phpDocType; + } + return $updatedDocTypes; + } private function cleanNullableMixed(UnionType $unionType) : Type { if (!TypeCombinator::containsNull($unionType)) { @@ -105,26 +163,13 @@ final class PhpDocNullableTypeHelper } private function resolveUpdatedPhpDocTypeFromPhpDocTypeAndPhpParserTypeNullInfo(Type $phpDocType, bool $isPhpParserTypeContainingNullType) : ?Type { - /** @var array<(NullType | UnionType)> $updatedDocTypes */ - $updatedDocTypes = []; - $phpDocTypeContainsNullType = \false; - if ($phpDocType instanceof UnionType) { - $phpDocTypeContainsNullType = TypeCombinator::containsNull($phpDocType); - foreach ($phpDocType->getTypes() as $subType) { - if ($subType instanceof NullType) { - continue; - } - $updatedDocTypes[] = $subType; - } - } else { - $updatedDocTypes[] = $phpDocType; - } - if (!$this->isItRequiredToRemoveOrAddNullTypeToUnion($phpDocTypeContainsNullType, $isPhpParserTypeContainingNullType)) { + $isPhpDocTypeContainingNullType = $this->hasNullType($phpDocType); + $isPhpDocTypeContainingClosureType = $this->hasClosureType($phpDocType); + $updatedDocTypes = $this->resolveUpdatedDocTypes($phpDocType); + if (!$this->isItRequiredToRemoveOrAddNullTypeToUnion($isPhpDocTypeContainingNullType, $isPhpParserTypeContainingNullType)) { return null; } - if ($isPhpParserTypeContainingNullType) { - $updatedDocTypes[] = new NullType(); - } + $updatedDocTypes = $this->appendOrPrependNullTypeIfAppropriate($isPhpParserTypeContainingNullType, $isPhpDocTypeContainingClosureType, $updatedDocTypes); return $this->composeUpdatedPhpDocType($updatedDocTypes); } } diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index 0d1210bef37..cffa2b89cd3 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -17,12 +17,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = 'effe4d38f68cfe64a38f7c2422befed3a872142e'; + public const PACKAGE_VERSION = 'a41ab99080e117c96cfb7107f58ab7b6d9281aa9'; /** * @api * @var string */ - public const RELEASE_DATE = '2022-09-11 13:59:51'; + public const RELEASE_DATE = '2022-09-12 09:20:11'; /** * @var int */ diff --git a/vendor/autoload.php b/vendor/autoload.php index 2d602f2d1df..9648f1514c7 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) { require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit38a04ff5251efa5c939ea18fa7ea2d80::getLoader(); +return ComposerAutoloaderInitd4775f137b5d69f259413200877cd83b::getLoader(); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 0f4ac5bbf5d..a4540ebdd51 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit38a04ff5251efa5c939ea18fa7ea2d80 +class ComposerAutoloaderInitd4775f137b5d69f259413200877cd83b { private static $loader; @@ -22,19 +22,19 @@ class ComposerAutoloaderInit38a04ff5251efa5c939ea18fa7ea2d80 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit38a04ff5251efa5c939ea18fa7ea2d80', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitd4775f137b5d69f259413200877cd83b', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit38a04ff5251efa5c939ea18fa7ea2d80', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitd4775f137b5d69f259413200877cd83b', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit38a04ff5251efa5c939ea18fa7ea2d80::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitd4775f137b5d69f259413200877cd83b::getInitializer($loader)); $loader->setClassMapAuthoritative(true); $loader->register(true); - $includeFiles = \Composer\Autoload\ComposerStaticInit38a04ff5251efa5c939ea18fa7ea2d80::$files; + $includeFiles = \Composer\Autoload\ComposerStaticInitd4775f137b5d69f259413200877cd83b::$files; foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire38a04ff5251efa5c939ea18fa7ea2d80($fileIdentifier, $file); + composerRequired4775f137b5d69f259413200877cd83b($fileIdentifier, $file); } return $loader; @@ -46,7 +46,7 @@ class ComposerAutoloaderInit38a04ff5251efa5c939ea18fa7ea2d80 * @param string $file * @return void */ -function composerRequire38a04ff5251efa5c939ea18fa7ea2d80($fileIdentifier, $file) +function composerRequired4775f137b5d69f259413200877cd83b($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 4673bcaf298..3424a6ef6a4 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit38a04ff5251efa5c939ea18fa7ea2d80 +class ComposerStaticInitd4775f137b5d69f259413200877cd83b { public static $files = array ( 'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php', @@ -3094,9 +3094,9 @@ class ComposerStaticInit38a04ff5251efa5c939ea18fa7ea2d80 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit38a04ff5251efa5c939ea18fa7ea2d80::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit38a04ff5251efa5c939ea18fa7ea2d80::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit38a04ff5251efa5c939ea18fa7ea2d80::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitd4775f137b5d69f259413200877cd83b::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitd4775f137b5d69f259413200877cd83b::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitd4775f137b5d69f259413200877cd83b::$classMap; }, null, ClassLoader::class); }