mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-31 08:20:53 +00:00
[TypeDeclaration] Improve PropertyTypeDeclarationRector to work with strict types (#1494)
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
7cdd03ed77
commit
f6c3e95d7b
|
@ -7760,7 +7760,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
|
||||
$services->set(TypedPropertyRector::class)
|
||||
->configure([
|
||||
TypedPropertyRector::CLASS_LIKE_TYPE_ONLY => false,
|
||||
TypedPropertyRector::PRIVATE_PROPERTY_ONLY => false,
|
||||
]);
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Rector\NodeTypeResolver\TypeComparator;
|
||||
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\ClassStringType;
|
||||
use PHPStan\Type\FloatType;
|
||||
use PHPStan\Type\IntegerType;
|
||||
use PHPStan\Type\StringType;
|
||||
|
@ -39,4 +40,50 @@ final class ScalarTypeComparator
|
|||
|
||||
return $secondType instanceof BooleanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g. first is string, second is bool
|
||||
*/
|
||||
public function areDifferentScalarTypes(Type $firstType, Type $secondType): bool
|
||||
{
|
||||
if (! $this->isScalarType($firstType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->isScalarType($secondType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// treat class-string and string the same
|
||||
if ($firstType instanceof ClassStringType && $secondType instanceof StringType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $firstType instanceof StringType) {
|
||||
return $firstType::class !== $secondType::class;
|
||||
}
|
||||
|
||||
if (! $secondType instanceof ClassStringType) {
|
||||
return $firstType::class !== $secondType::class;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isScalarType(Type $type): bool
|
||||
{
|
||||
if ($type instanceof StringType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($type instanceof FloatType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($type instanceof IntegerType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $type instanceof BooleanType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,13 @@ final class TypeComparator
|
|||
$phpParserNodeType = $this->normalizeConstantBooleanType($phpParserNodeType);
|
||||
$phpStanDocType = $this->normalizeConstantBooleanType($phpStanDocType);
|
||||
|
||||
if (! $this->areTypesEqual($phpParserNodeType, $phpStanDocType)) {
|
||||
// is scalar replace by another - remove it?
|
||||
$areDifferentScalarTypes = $this->scalarTypeComparator->areDifferentScalarTypes(
|
||||
$phpParserNodeType,
|
||||
$phpStanDocType
|
||||
);
|
||||
|
||||
if (! $areDifferentScalarTypes && ! $this->areTypesEqual($phpParserNodeType, $phpStanDocType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -608,3 +608,8 @@ parameters:
|
|||
-
|
||||
message: '#Casting to int something that.{1}s already int#'
|
||||
path: packages/NodeTypeResolver/NodeTypeResolver/ScalarTypeResolver.php #46
|
||||
|
||||
# will be desolved
|
||||
-
|
||||
path: rules/Php74/Rector/Property/TypedPropertyRector.php
|
||||
message: '#Class cognitive complexity is 31, keep it under 30#'
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
namespace Rector\Tests\Php74\Rector\Property\TypedPropertyRector\Fixture;
|
||||
|
||||
/**
|
||||
* @template T of object
|
||||
* @template TType of object
|
||||
*/
|
||||
final class SomeGenericObjectType
|
||||
{
|
||||
/**
|
||||
* @var T
|
||||
* @var TType
|
||||
*/
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* @param T $command
|
||||
* @param TType $command
|
||||
*/
|
||||
public function __construct(object $command)
|
||||
{
|
||||
|
@ -27,17 +27,17 @@ final class SomeGenericObjectType
|
|||
namespace Rector\Tests\Php74\Rector\Property\TypedPropertyRector\Fixture;
|
||||
|
||||
/**
|
||||
* @template T of object
|
||||
* @template TType of object
|
||||
*/
|
||||
final class SomeGenericObjectType
|
||||
{
|
||||
/**
|
||||
* @var T
|
||||
* @var TType
|
||||
*/
|
||||
private object $command;
|
||||
|
||||
/**
|
||||
* @param T $command
|
||||
* @param TType $command
|
||||
*/
|
||||
public function __construct(object $command)
|
||||
{
|
||||
|
|
|
@ -28,6 +28,6 @@ final class ImportedTest extends AbstractRectorTestCase
|
|||
|
||||
public function provideConfigFilePath(): string
|
||||
{
|
||||
return __DIR__ . '/config/imported_type.php';
|
||||
return __DIR__ . '/config/import_names.php';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Php74\Rector\Property\TypedPropertyRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TypedPropertyRector::class)
|
||||
->configure([
|
||||
TypedPropertyRector::CLASS_LIKE_TYPE_ONLY => true,
|
||||
]);
|
||||
};
|
|
@ -6,12 +6,15 @@ use Rector\Core\Configuration\Option;
|
|||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRector;
|
||||
use Rector\Php74\Rector\Property\TypedPropertyRector;
|
||||
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TypedPropertyRector::class);
|
||||
|
||||
$services->set(TypedPropertyFromStrictGetterMethodReturnTypeRector::class);
|
||||
|
||||
// should be ignored if typed property is used
|
||||
$services->set(RemoveNullPropertyInitializationRector::class);
|
||||
|
||||
|
|
|
@ -3,16 +3,15 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\Php74\Rector\Property\TypedPropertyRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
|
||||
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TypedPropertyRector::class)
|
||||
->configure([
|
||||
TypedPropertyRector::CLASS_LIKE_TYPE_ONLY => true,
|
||||
]);
|
||||
$services->set(TypedPropertyRector::class);
|
||||
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::UNION_TYPES);
|
||||
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
|
||||
};
|
|
@ -1,128 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
|
||||
final class GetterType
|
||||
{
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $language;
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function hasLanguage(): bool
|
||||
{
|
||||
return $this->language !== null;
|
||||
}
|
||||
|
||||
public function getLanguage()
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
public function setLanguage(string $language): void
|
||||
{
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): void
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
|
||||
final class GetterType
|
||||
{
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
* @var string|null
|
||||
*/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
* @var string|null
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
* @var string|null
|
||||
*/
|
||||
private $language;
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function hasLanguage(): bool
|
||||
{
|
||||
return $this->language !== null;
|
||||
}
|
||||
|
||||
public function getLanguage()
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
public function setLanguage(string $language): void
|
||||
{
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): void
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
final class GetterTypeFromVarDoc
|
||||
{
|
||||
private $surname;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSurname()
|
||||
{
|
||||
return $this->surname;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
final class GetterTypeFromVarDoc
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $surname;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSurname()
|
||||
{
|
||||
return $this->surname;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector\FixturePhp74;
|
||||
|
||||
class SkipTypedProperty
|
||||
{
|
||||
public string $name = 'hey';
|
||||
}
|
|
@ -2,10 +2,15 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::TYPED_PROPERTIES - 1);
|
||||
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(PropertyTypeDeclarationRector::class);
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigura
|
|||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::TYPED_PROPERTIES);
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::UNION_TYPES);
|
||||
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(PropertyTypeDeclarationRector::class);
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector\FixturePhp73;
|
||||
|
||||
use stdClass;
|
||||
|
||||
final class OnlyVarDocProperty
|
||||
{
|
||||
private $stdClass;
|
||||
|
||||
public function __construct(stdClass $stdClass)
|
||||
{
|
||||
$this->stdClass = $stdClass;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector\FixturePhp73;
|
||||
|
||||
use stdClass;
|
||||
|
||||
final class OnlyVarDocProperty
|
||||
{
|
||||
/**
|
||||
* @var \stdClass
|
||||
*/
|
||||
private $stdClass;
|
||||
|
||||
public function __construct(stdClass $stdClass)
|
||||
{
|
||||
$this->stdClass = $stdClass;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Php74\Rector\Property\TypedPropertyRector;
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class ClassLikeTypesOnlyTest extends AbstractRectorTestCase
|
||||
final class TypedPropertyFromStrictConstructorPhp73RectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
|
@ -23,11 +23,11 @@ final class ClassLikeTypesOnlyTest extends AbstractRectorTestCase
|
|||
*/
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureClassLikeTypeOnly');
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixturePhp73');
|
||||
}
|
||||
|
||||
public function provideConfigFilePath(): string
|
||||
{
|
||||
return __DIR__ . '/config/class_types_only.php';
|
||||
return __DIR__ . '/config/configured_php73.php';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TypedPropertyFromStrictConstructorRector::class);
|
||||
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::TYPED_PROPERTIES - 1);
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector\FixturePhp73;
|
||||
|
||||
final class PrivatePropertyWithVarDoc
|
||||
{
|
||||
public $name;
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector\FixturePhp73;
|
||||
|
||||
final class PrivatePropertyWithVarDoc
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,16 +2,13 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector;
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
/**
|
||||
* @requires PHP 7.4
|
||||
*/
|
||||
final class Php74Test extends AbstractRectorTestCase
|
||||
final class TypedPropertyFromStrictGetterMethodReturnTypePhp73RectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
|
@ -26,11 +23,11 @@ final class Php74Test extends AbstractRectorTestCase
|
|||
*/
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixturePhp74');
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixturePhp73');
|
||||
}
|
||||
|
||||
public function provideConfigFilePath(): string
|
||||
{
|
||||
return __DIR__ . '/config/typed_property.php';
|
||||
return __DIR__ . '/config/rule_php73.php';
|
||||
}
|
||||
}
|
|
@ -2,10 +2,15 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TypedPropertyFromStrictGetterMethodReturnTypeRector::class);
|
||||
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::TYPED_PROPERTIES);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(TypedPropertyFromStrictGetterMethodReturnTypeRector::class);
|
||||
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::TYPED_PROPERTIES - 1);
|
||||
};
|
|
@ -12,6 +12,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
|
|||
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\Generic\TemplateObjectWithoutClassType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
|
@ -49,6 +50,10 @@ final class VarTagRemover
|
|||
|
||||
public function removeVarPhpTagValueNodeIfNotComment(Expression | Property | Param $node, Type $type): void
|
||||
{
|
||||
if ($type instanceof TemplateObjectWithoutClassType) {
|
||||
return;
|
||||
}
|
||||
|
||||
// keep doctrine collection narrow type
|
||||
if ($this->doctrineTypeAnalyzer->isDoctrineCollectionWithIterableUnionType($type)) {
|
||||
return;
|
||||
|
|
|
@ -7,12 +7,10 @@ namespace Rector\Php74\Rector\Property;
|
|||
use PhpParser\Node;
|
||||
use PhpParser\Node\ComplexType;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PHPStan\Type\Generic\TemplateType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\NullType;
|
||||
|
@ -28,10 +26,8 @@ use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
|
|||
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Php74\TypeAnalyzer\ObjectTypeAnalyzer;
|
||||
use Rector\Php74\TypeAnalyzer\PropertyUnionTypeResolver;
|
||||
use Rector\PHPStanStaticTypeMapper\DoctrineTypeAnalyzer;
|
||||
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
|
||||
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
|
||||
use Rector\VendorLocker\VendorLockResolver;
|
||||
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
|
||||
|
@ -45,25 +41,14 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
|||
* @see \Rector\Tests\Php74\Rector\Property\TypedPropertyRector\ClassLikeTypesOnlyTest
|
||||
* @see \Rector\Tests\Php74\Rector\Property\TypedPropertyRector\DoctrineTypedPropertyRectorTest
|
||||
* @see \Rector\Tests\Php74\Rector\Property\TypedPropertyRector\ImportedTest
|
||||
* @see \Rector\Tests\Php74\Rector\Property\TypedPropertyRector\UnionTypedPropertyRectorTest
|
||||
*/
|
||||
final class TypedPropertyRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface, MinPhpVersionInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
final public const CLASS_LIKE_TYPE_ONLY = 'class_like_type_only';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
final public const PRIVATE_PROPERTY_ONLY = 'PRIVATE_PROPERTY_ONLY';
|
||||
|
||||
/**
|
||||
* Useful for refactoring of huge applications. Taking types first narrows scope
|
||||
*/
|
||||
private bool $classLikeTypeOnly = false;
|
||||
|
||||
/**
|
||||
* If want to keep BC, it can be set to true
|
||||
* @see https://3v4l.org/spl4P
|
||||
|
@ -75,11 +60,9 @@ final class TypedPropertyRector extends AbstractRector implements AllowEmptyConf
|
|||
private readonly VendorLockResolver $vendorLockResolver,
|
||||
private readonly DoctrineTypeAnalyzer $doctrineTypeAnalyzer,
|
||||
private readonly VarTagRemover $varTagRemover,
|
||||
private readonly ReflectionProvider $reflectionProvider,
|
||||
private readonly PropertyFetchAnalyzer $propertyFetchAnalyzer,
|
||||
private readonly FamilyRelationsAnalyzer $familyRelationsAnalyzer,
|
||||
private readonly PropertyAnalyzer $propertyAnalyzer,
|
||||
private readonly PropertyUnionTypeResolver $propertyUnionTypeResolver,
|
||||
private readonly AstResolver $astResolver,
|
||||
private readonly ObjectTypeAnalyzer $objectTypeAnalyzer
|
||||
) {
|
||||
|
@ -109,7 +92,6 @@ final class SomeClass
|
|||
CODE_SAMPLE
|
||||
,
|
||||
[
|
||||
self::CLASS_LIKE_TYPE_ONLY => false,
|
||||
self::PRIVATE_PROPERTY_ONLY => false,
|
||||
]
|
||||
),
|
||||
|
@ -160,7 +142,7 @@ CODE_SAMPLE
|
|||
|
||||
$propertyTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($varType, TypeKind::PROPERTY());
|
||||
|
||||
if ($this->isNullOrNonClassLikeTypeOrMixedOrVendorLockedIn($propertyTypeNode, $node, $varType)) {
|
||||
if ($this->isNullOrNonClassLikeTypeOrMixedOrVendorLockedIn($propertyTypeNode, $node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -190,7 +172,6 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function configure(array $configuration): void
|
||||
{
|
||||
$this->classLikeTypeOnly = $configuration[self::CLASS_LIKE_TYPE_ONLY] ?? false;
|
||||
$this->privatePropertyOnly = $configuration[self::PRIVATE_PROPERTY_ONLY] ?? false;
|
||||
}
|
||||
|
||||
|
@ -202,19 +183,11 @@ CODE_SAMPLE
|
|||
private function isNullOrNonClassLikeTypeOrMixedOrVendorLockedIn(
|
||||
Name | ComplexType | null $node,
|
||||
Property $property,
|
||||
Type $type
|
||||
): bool {
|
||||
if (! $node instanceof Node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$type = $this->propertyUnionTypeResolver->resolve($node, $type);
|
||||
|
||||
// is not class-type and should be skipped
|
||||
if ($this->shouldSkipNonClassLikeType($node, $type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// false positive
|
||||
if (! $node instanceof Name) {
|
||||
return $this->vendorLockResolver->isPropertyTypeChangeVendorLockedIn($property);
|
||||
|
@ -227,29 +200,6 @@ CODE_SAMPLE
|
|||
return true;
|
||||
}
|
||||
|
||||
private function shouldSkipNonClassLikeType(Name|ComplexType $node, Type $type): bool
|
||||
{
|
||||
// unwrap nullable type
|
||||
if ($node instanceof NullableType) {
|
||||
$node = $node->type;
|
||||
}
|
||||
|
||||
$typeName = $this->getName($node);
|
||||
if ($typeName === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->classLikeTypeOnly) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($type instanceof AliasedObjectType) {
|
||||
$typeName = $type->getFullyQualifiedName();
|
||||
}
|
||||
|
||||
return ! $this->reflectionProvider->hasClass($typeName);
|
||||
}
|
||||
|
||||
private function removeDefaultValueForDoctrineCollection(Property $property, Type $propertyType): void
|
||||
{
|
||||
if (! $this->doctrineTypeAnalyzer->isDoctrineCollectionWithIterableUnionType($propertyType)) {
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php74\TypeAnalyzer;
|
||||
|
||||
use PhpParser\Node\ComplexType;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PHPStan\Type\NullType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
|
||||
final class PropertyUnionTypeResolver
|
||||
{
|
||||
public function resolve(Name|ComplexType $phpUnionType, Type $possibleUnionType): Type
|
||||
{
|
||||
if (! $phpUnionType instanceof NullableType) {
|
||||
return $possibleUnionType;
|
||||
}
|
||||
|
||||
if (! $possibleUnionType instanceof UnionType) {
|
||||
return $possibleUnionType;
|
||||
}
|
||||
|
||||
$types = $possibleUnionType->getTypes();
|
||||
foreach ($types as $type) {
|
||||
if (! $type instanceof NullType) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
return $possibleUnionType;
|
||||
}
|
||||
}
|
|
@ -6,16 +6,21 @@ namespace Rector\TypeDeclaration\Rector\Property;
|
|||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\UnionType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\NullType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
|
||||
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @deprecated Split to smaller specific rules.
|
||||
* @see \Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector\PropertyTypeDeclarationRectorTest
|
||||
*/
|
||||
final class PropertyTypeDeclarationRector extends AbstractRector
|
||||
|
@ -96,6 +101,10 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
if ($this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::TYPED_PROPERTIES)) {
|
||||
return $this->completeTypedProperty($type, $node, $phpDocInfo);
|
||||
}
|
||||
|
||||
$this->phpDocTypeChanger->changeVarType($phpDocInfo, $type);
|
||||
|
||||
return $node;
|
||||
|
@ -112,4 +121,21 @@ CODE_SAMPLE
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function completeTypedProperty(Type $type, Property $property, PhpDocInfo $phpDocInfo): Property
|
||||
{
|
||||
$propertyTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($type, TypeKind::PROPERTY());
|
||||
if ($propertyTypeNode instanceof UnionType) {
|
||||
if ($this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::UNION_TYPES)) {
|
||||
$property->type = $propertyTypeNode;
|
||||
return $property;
|
||||
}
|
||||
|
||||
$this->phpDocTypeChanger->changeVarType($phpDocInfo, $type);
|
||||
return $property;
|
||||
}
|
||||
|
||||
$property->type = $propertyTypeNode;
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,23 +8,24 @@ use PhpParser\Node;
|
|||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
|
||||
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
|
||||
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer\ConstructorPropertyTypeInferer;
|
||||
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector\TypedPropertyFromStrictConstructorRectorTest
|
||||
*/
|
||||
final class TypedPropertyFromStrictConstructorRector extends AbstractRector implements MinPhpVersionInterface
|
||||
final class TypedPropertyFromStrictConstructorRector extends AbstractRector
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ConstructorPropertyTypeInferer $constructorPropertyTypeInferer,
|
||||
private readonly VarTagRemover $varTagRemover
|
||||
private readonly VarTagRemover $varTagRemover,
|
||||
private readonly PhpDocTypeChanger $phpDocTypeChanger
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -86,8 +87,14 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$propertyTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($varType, TypeKind::PROPERTY());
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
|
||||
|
||||
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::TYPED_PROPERTIES)) {
|
||||
$this->phpDocTypeChanger->changeVarType($phpDocInfo, $varType);
|
||||
return $node;
|
||||
}
|
||||
|
||||
$propertyTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($varType, TypeKind::PROPERTY());
|
||||
if (! $propertyTypeNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
|
@ -95,7 +102,6 @@ CODE_SAMPLE
|
|||
$node->type = $propertyTypeNode;
|
||||
$node->props[0]->default = null;
|
||||
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
|
||||
$this->varTagRemover->removeVarTagIfUseless($phpDocInfo, $node);
|
||||
|
||||
return $node;
|
||||
|
|
|
@ -11,23 +11,25 @@ use PHPStan\Analyser\Scope;
|
|||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeCombinator;
|
||||
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
|
||||
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer\GetterTypeDeclarationPropertyTypeInferer;
|
||||
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector\TypedPropertyFromStrictGetterMethodReturnTypeRectorTest
|
||||
* @todo make generic
|
||||
*/
|
||||
final class TypedPropertyFromStrictGetterMethodReturnTypeRector extends AbstractRector implements MinPhpVersionInterface
|
||||
final class TypedPropertyFromStrictGetterMethodReturnTypeRector extends AbstractRector
|
||||
{
|
||||
public function __construct(
|
||||
private readonly GetterTypeDeclarationPropertyTypeInferer $getterTypeDeclarationPropertyTypeInferer,
|
||||
private readonly PhpDocTypeChanger $phpDocTypeChanger,
|
||||
private readonly VarTagRemover $varTagRemover
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -90,6 +92,12 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::TYPED_PROPERTIES)) {
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
|
||||
$this->phpDocTypeChanger->changeVarType($phpDocInfo, $getterReturnType);
|
||||
return $node;
|
||||
}
|
||||
|
||||
// if property is public, it should be nullable
|
||||
if ($node->isPublic() && ! TypeCombinator::containsNull($getterReturnType)) {
|
||||
$getterReturnType = TypeCombinator::addNull($getterReturnType);
|
||||
|
@ -103,6 +111,9 @@ CODE_SAMPLE
|
|||
$node->type = $propertyType;
|
||||
$this->decorateDefaultNull($getterReturnType, $node);
|
||||
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
|
||||
$this->varTagRemover->removeVarTagIfUseless($phpDocInfo, $node);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,9 @@ use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
|||
use Rector\StaticTypeMapper\StaticTypeMapper;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
|
||||
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
|
||||
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
|
||||
|
||||
final class ConstructorPropertyTypeInferer implements PropertyTypeInfererInterface
|
||||
final class ConstructorPropertyTypeInferer
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClassMethodPropertyFetchManipulator $classMethodPropertyFetchManipulator,
|
||||
|
@ -75,11 +74,6 @@ final class ConstructorPropertyTypeInferer implements PropertyTypeInfererInterfa
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 800;
|
||||
}
|
||||
|
||||
private function resolveFromParamType(Param $param, ClassMethod $classMethod, string $propertyName): Type
|
||||
{
|
||||
$type = $this->resolveParamTypeToPHPStanType($param);
|
||||
|
|
|
@ -19,6 +19,9 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
|||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
|
||||
|
||||
/**
|
||||
* @deprecated Move to rector-doctrine, under code quality
|
||||
*/
|
||||
final class DoctrineColumnPropertyTypeInferer implements PropertyTypeInfererInterface
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,9 @@ use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
|
|||
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
|
||||
use Rector\TypeDeclaration\PhpDoc\ShortClassExpander;
|
||||
|
||||
/**
|
||||
* @deprecated Move to rector-doctrine, under code quality
|
||||
*/
|
||||
final class DoctrineRelationPropertyTypeInferer implements PropertyTypeInfererInterface
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
|
||||
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\Core\PhpParser\AstResolver;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
|
||||
use Rector\TypeDeclaration\FunctionLikeReturnTypeResolver;
|
||||
use Rector\TypeDeclaration\NodeAnalyzer\ClassMethodAndPropertyAnalyzer;
|
||||
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer\ReturnedNodesReturnTypeInferer;
|
||||
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer\ReturnTagReturnTypeInferer;
|
||||
|
||||
final class GetterPropertyTypeInferer implements PropertyTypeInfererInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ReturnTagReturnTypeInferer $returnTagReturnTypeInferer,
|
||||
private readonly ReturnedNodesReturnTypeInferer $returnedNodesReturnTypeInferer,
|
||||
private readonly FunctionLikeReturnTypeResolver $functionLikeReturnTypeResolver,
|
||||
private readonly ClassMethodAndPropertyAnalyzer $classMethodAndPropertyAnalyzer,
|
||||
private readonly NodeNameResolver $nodeNameResolver,
|
||||
private readonly BetterNodeFinder $betterNodeFinder,
|
||||
private readonly AstResolver $astResolver
|
||||
) {
|
||||
}
|
||||
|
||||
public function inferProperty(Property $property): ?Type
|
||||
{
|
||||
$class = $this->betterNodeFinder->findParentType($property, Class_::class);
|
||||
if (! $class instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $propertyName */
|
||||
$propertyName = $this->nodeNameResolver->getName($property);
|
||||
|
||||
$returnTypes = [];
|
||||
|
||||
$classAndTraitMethods = $this->resolveClassAndTraitMethods($class);
|
||||
|
||||
foreach ($classAndTraitMethods as $classAndTraitMethod) {
|
||||
if (! $this->classMethodAndPropertyAnalyzer->hasClassMethodOnlyStatementReturnOfPropertyFetch(
|
||||
$classAndTraitMethod,
|
||||
$propertyName
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$returnType = $this->inferClassMethodReturnType($classAndTraitMethod);
|
||||
if ($returnType instanceof MixedType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$returnTypes[] = $returnType;
|
||||
}
|
||||
|
||||
if ($returnTypes === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($returnTypes) === 1) {
|
||||
return $returnTypes[0];
|
||||
}
|
||||
|
||||
return new UnionType($returnTypes);
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 1700;
|
||||
}
|
||||
|
||||
private function inferClassMethodReturnType(ClassMethod $classMethod): Type
|
||||
{
|
||||
$returnTypeDeclarationType = $this->functionLikeReturnTypeResolver->resolveFunctionLikeReturnTypeToPHPStanType(
|
||||
$classMethod
|
||||
);
|
||||
|
||||
if (! $returnTypeDeclarationType instanceof MixedType) {
|
||||
return $returnTypeDeclarationType;
|
||||
}
|
||||
|
||||
$inferedType = $this->returnedNodesReturnTypeInferer->inferFunctionLike($classMethod);
|
||||
if (! $inferedType instanceof MixedType) {
|
||||
return $inferedType;
|
||||
}
|
||||
|
||||
return $this->returnTagReturnTypeInferer->inferFunctionLike($classMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ClassMethod[]
|
||||
*/
|
||||
private function resolveClassAndTraitMethods(Class_ $class): array
|
||||
{
|
||||
$classAndTraitMethods = $class->getMethods();
|
||||
|
||||
foreach ($class->getTraitUses() as $traitUse) {
|
||||
foreach ($traitUse->traits as $traitName) {
|
||||
$trait = $this->astResolver->resolveClassFromName($traitName->toString());
|
||||
if (! $trait instanceof Trait_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classAndTraitMethods = array_merge($classAndTraitMethods, $trait->getMethods());
|
||||
}
|
||||
}
|
||||
|
||||
return $classAndTraitMethods;
|
||||
}
|
||||
}
|
|
@ -12,11 +12,10 @@ use PHPStan\Type\MixedType;
|
|||
use PHPStan\Type\Type;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface;
|
||||
use Rector\TypeDeclaration\FunctionLikeReturnTypeResolver;
|
||||
use Rector\TypeDeclaration\NodeAnalyzer\ClassMethodAndPropertyAnalyzer;
|
||||
|
||||
final class GetterTypeDeclarationPropertyTypeInferer implements PropertyTypeInfererInterface
|
||||
final class GetterTypeDeclarationPropertyTypeInferer
|
||||
{
|
||||
public function __construct(
|
||||
private readonly FunctionLikeReturnTypeResolver $functionLikeReturnTypeResolver,
|
||||
|
@ -60,9 +59,4 @@ final class GetterTypeDeclarationPropertyTypeInferer implements PropertyTypeInfe
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 630;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Php74\Rector\Property\TypedPropertyRector;
|
||||
use Rector\Php80\Rector\Class_\StringableForToStringRector;
|
||||
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictGetterMethodReturnTypeRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(StringableForToStringRector::class);
|
||||
$services->set(TypedPropertyRector::class);
|
||||
$services->set(TypedPropertyFromStrictGetterMethodReturnTypeRector::class);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user