Updated Rector to commit 52b665436c0f2161619b265caa3f2a65be5604dc

52b665436c [PHP83] Implements a rule to add types to class constants (#5290)
This commit is contained in:
Tomas Votruba 2023-12-03 14:59:47 +00:00
parent 1bcbe800e1
commit f9c1f58ffc
8 changed files with 249 additions and 6 deletions

View File

@ -4,7 +4,6 @@ declare (strict_types=1);
namespace RectorPrefix202312;
use Rector\Config\RectorConfig;
use Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector;
return static function (RectorConfig $rectorConfig) : void {
$rectorConfig->rules([AddOverrideAttributeToOverriddenMethodsRector::class]);
$rectorConfig->rules([\Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector::class, \Rector\Php83\Rector\ClassConst\AddTypeToConstRector::class]);
};

View File

@ -1,4 +1,4 @@
# 351 Rules Overview
# 353 Rules Overview
<br>
@ -44,7 +44,7 @@
- [Php82](#php82) (4)
- [Php83](#php83) (1)
- [Php83](#php83) (2)
- [Privatization](#privatization) (4)
@ -5263,6 +5263,22 @@ Add override attribute to overridden methods
<br>
### AddTypeToConstRector
Add const to type
- class: [`Rector\Php83\Rector\ClassConst\AddTypeToConstRector`](../rules/Php83/Rector/ClassConst/AddTypeToConstRector.php)
```diff
final class SomeClass
{
- public const TYPE = 'some_type';
+ public const string TYPE = 'some_type';
}
```
<br>
## Privatization
### FinalizeClassesWithoutChildrenRector

View File

@ -0,0 +1,200 @@
<?php
declare (strict_types=1);
namespace Rector\Php83\Rector\ClassConst;
use PhpParser\Node;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MissingConstantFromReflectionException;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Exception\FullyQualifiedNameNotAutoloadedException;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\Php83\Rector\ClassConst\AddTypeToConstRector\AddTypeToConstRectorTest
*/
class AddTypeToConstRector extends AbstractRector implements MinPhpVersionInterface
{
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
}
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Add const to type', [new CodeSample(<<<'CODE_SAMPLE'
final class SomeClass
{
public const TYPE = 'some_type';
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
final class SomeClass
{
public const string TYPE = 'some_type';
}
CODE_SAMPLE
)]);
}
public function getNodeTypes() : array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node) : ?\PhpParser\Node\Stmt\Class_
{
if ($node->isAbstract()) {
return null;
}
$consts = \array_filter($node->stmts, function (Node $stmt) {
return $stmt instanceof Node\Stmt\ClassConst;
});
if ($consts === []) {
return null;
}
try {
$parents = $this->getParents($node);
$implementations = $this->getImplementations($node);
$traits = $this->getTraits($node);
} catch (FullyQualifiedNameNotAutoloadedException $exception) {
return null;
}
$changes = \false;
foreach ($consts as $const) {
// If a type is set, skip
if ($const->type !== null) {
continue;
}
foreach ($const->consts as $constNode) {
if ($this->shouldSkipDueToInheritance($constNode, $parents, $implementations, $traits)) {
continue;
}
if ($this->canBeInheritied($const, $node)) {
continue;
}
$valueType = $this->findValueType($constNode->value);
}
if (($valueType ?? null) === null) {
continue;
}
$const->type = $valueType;
$changes = \true;
}
if (!$changes) {
return null;
}
return $node;
}
public function provideMinPhpVersion() : int
{
return PhpVersionFeature::TYPED_CLASS_CONSTANTS;
}
/**
* @param ClassReflection[] $parents
* @param ClassReflection[] $implementations
* @param ClassReflection[] $traits
*/
public function shouldSkipDueToInheritance(Node\Const_ $constNode, array $parents, array $implementations, array $traits) : bool
{
foreach ([$parents, $implementations, $traits] as $inheritance) {
foreach ($inheritance as $inheritanceItem) {
if ($constNode->name->name === '') {
continue;
}
try {
$inheritanceItem->getConstant($constNode->name->name);
return \true;
} catch (MissingConstantFromReflectionException $exception) {
}
}
}
return \false;
}
private function findValueType(Node\Expr $value) : ?Node\Identifier
{
if ($value instanceof Node\Scalar\String_) {
return new Node\Identifier('string');
}
if ($value instanceof Node\Scalar\LNumber) {
return new Node\Identifier('int');
}
if ($value instanceof Node\Scalar\DNumber) {
return new Node\Identifier('float');
}
if ($value instanceof Node\Expr\ConstFetch && $value->name->toLowerString() !== 'null') {
return new Node\Identifier('bool');
}
if ($value instanceof Node\Expr\ConstFetch && $value->name->toLowerString() === 'null') {
return new Node\Identifier('null');
}
if ($value instanceof Node\Expr\Array_) {
return new Node\Identifier('array');
}
return null;
}
/**
* @return ClassReflection[]
*/
private function getParents(Class_ $class) : array
{
$parents = \array_filter([$class->extends]);
return \array_map(function (Node\Name $name) : ClassReflection {
if (!$name instanceof FullyQualified) {
throw new FullyQualifiedNameNotAutoloadedException($name);
}
if ($this->reflectionProvider->hasClass($name->toString())) {
return $this->reflectionProvider->getClass($name->toString());
}
throw new FullyQualifiedNameNotAutoloadedException($name);
}, $parents);
}
/**
* @return ClassReflection[]
*/
private function getImplementations(Class_ $class) : array
{
return \array_map(function (Node\Name $name) : ClassReflection {
if (!$name instanceof FullyQualified) {
throw new FullyQualifiedNameNotAutoloadedException($name);
}
if ($this->reflectionProvider->hasClass($name->toString())) {
return $this->reflectionProvider->getClass($name->toString());
}
throw new FullyQualifiedNameNotAutoloadedException($name);
}, $class->implements);
}
/**
* @return ClassReflection[]
*/
private function getTraits(Class_ $node) : array
{
$traits = [];
foreach ($node->getTraitUses() as $traitUse) {
$traits = \array_merge($traits, $traitUse->traits);
}
return \array_map(function (Node\Name $name) : ClassReflection {
if (!$name instanceof FullyQualified) {
throw new FullyQualifiedNameNotAutoloadedException($name);
}
if ($this->reflectionProvider->hasClass($name->toString())) {
return $this->reflectionProvider->getClass($name->toString());
}
throw new FullyQualifiedNameNotAutoloadedException($name);
}, $traits);
}
private function canBeInheritied(Node\Stmt\ClassConst $constNode, Class_ $node) : bool
{
return !$node->isFinal() && !$constNode->isPrivate();
}
}

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = 'ea5b331e7ea67a03b4c3f162c566a8dbfd74d55d';
public const PACKAGE_VERSION = '52b665436c0f2161619b265caa3f2a65be5604dc';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-12-03 13:22:40';
public const RELEASE_DATE = '2023-12-03 15:57:42';
/**
* @var int
*/

View File

@ -0,0 +1,19 @@
<?php
declare (strict_types=1);
namespace Rector\Core\Exception;
use PhpParser\Node\Name;
use RuntimeException;
class FullyQualifiedNameNotAutoloadedException extends RuntimeException
{
/**
* @var \PhpParser\Node\Name
*/
protected $name;
public function __construct(Name $name)
{
$this->name = $name;
parent::__construct(\sprintf('%s was not autoloaded', $name->toString()));
}
}

View File

@ -527,4 +527,9 @@ final class PhpVersionFeature
* @var int
*/
public const OVERRIDE_ATTRIBUTE = \Rector\Core\ValueObject\PhpVersion::PHP_83;
/**
* @see https://wiki.php.net/rfc/typed_class_constants
* @var int
*/
public const TYPED_CLASS_CONSTANTS = \Rector\Core\ValueObject\PhpVersion::PHP_83;
}

View File

@ -1204,6 +1204,7 @@ return array(
'Rector\\Core\\Error\\ExceptionCorrector' => $baseDir . '/src/Error/ExceptionCorrector.php',
'Rector\\Core\\Exception\\Cache\\CachingException' => $baseDir . '/src/Exception/Cache/CachingException.php',
'Rector\\Core\\Exception\\Configuration\\InvalidConfigurationException' => $baseDir . '/src/Exception/Configuration/InvalidConfigurationException.php',
'Rector\\Core\\Exception\\FullyQualifiedNameNotAutoloadedException' => $baseDir . '/src/Exception/FullyQualifiedNameNotAutoloadedException.php',
'Rector\\Core\\Exception\\NotImplementedYetException' => $baseDir . '/src/Exception/NotImplementedYetException.php',
'Rector\\Core\\Exception\\Reflection\\MissingPrivatePropertyException' => $baseDir . '/src/Exception/Reflection/MissingPrivatePropertyException.php',
'Rector\\Core\\Exception\\ShouldNotHappenException' => $baseDir . '/src/Exception/ShouldNotHappenException.php',
@ -1914,6 +1915,7 @@ return array(
'Rector\\Php82\\Rector\\FuncCall\\Utf8DecodeEncodeToMbConvertEncodingRector' => $baseDir . '/rules/Php82/Rector/FuncCall/Utf8DecodeEncodeToMbConvertEncodingRector.php',
'Rector\\Php82\\Rector\\New_\\FilesystemIteratorSkipDotsRector' => $baseDir . '/rules/Php82/Rector/New_/FilesystemIteratorSkipDotsRector.php',
'Rector\\Php82\\Rector\\Param\\AddSensitiveParameterAttributeRector' => $baseDir . '/rules/Php82/Rector/Param/AddSensitiveParameterAttributeRector.php',
'Rector\\Php83\\Rector\\ClassConst\\AddTypeToConstRector' => $baseDir . '/rules/Php83/Rector/ClassConst/AddTypeToConstRector.php',
'Rector\\Php83\\Rector\\ClassMethod\\AddOverrideAttributeToOverriddenMethodsRector' => $baseDir . '/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php',
'Rector\\PhpAttribute\\AnnotationToAttributeMapper' => $baseDir . '/packages/PhpAttribute/AnnotationToAttributeMapper.php',
'Rector\\PhpAttribute\\AnnotationToAttributeMapper\\ArrayAnnotationToAttributeMapper' => $baseDir . '/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayAnnotationToAttributeMapper.php',

View File

@ -1422,6 +1422,7 @@ class ComposerStaticInita55c41c7fa52abd86138c6f32df1d185
'Rector\\Core\\Error\\ExceptionCorrector' => __DIR__ . '/../..' . '/src/Error/ExceptionCorrector.php',
'Rector\\Core\\Exception\\Cache\\CachingException' => __DIR__ . '/../..' . '/src/Exception/Cache/CachingException.php',
'Rector\\Core\\Exception\\Configuration\\InvalidConfigurationException' => __DIR__ . '/../..' . '/src/Exception/Configuration/InvalidConfigurationException.php',
'Rector\\Core\\Exception\\FullyQualifiedNameNotAutoloadedException' => __DIR__ . '/../..' . '/src/Exception/FullyQualifiedNameNotAutoloadedException.php',
'Rector\\Core\\Exception\\NotImplementedYetException' => __DIR__ . '/../..' . '/src/Exception/NotImplementedYetException.php',
'Rector\\Core\\Exception\\Reflection\\MissingPrivatePropertyException' => __DIR__ . '/../..' . '/src/Exception/Reflection/MissingPrivatePropertyException.php',
'Rector\\Core\\Exception\\ShouldNotHappenException' => __DIR__ . '/../..' . '/src/Exception/ShouldNotHappenException.php',
@ -2132,6 +2133,7 @@ class ComposerStaticInita55c41c7fa52abd86138c6f32df1d185
'Rector\\Php82\\Rector\\FuncCall\\Utf8DecodeEncodeToMbConvertEncodingRector' => __DIR__ . '/../..' . '/rules/Php82/Rector/FuncCall/Utf8DecodeEncodeToMbConvertEncodingRector.php',
'Rector\\Php82\\Rector\\New_\\FilesystemIteratorSkipDotsRector' => __DIR__ . '/../..' . '/rules/Php82/Rector/New_/FilesystemIteratorSkipDotsRector.php',
'Rector\\Php82\\Rector\\Param\\AddSensitiveParameterAttributeRector' => __DIR__ . '/../..' . '/rules/Php82/Rector/Param/AddSensitiveParameterAttributeRector.php',
'Rector\\Php83\\Rector\\ClassConst\\AddTypeToConstRector' => __DIR__ . '/../..' . '/rules/Php83/Rector/ClassConst/AddTypeToConstRector.php',
'Rector\\Php83\\Rector\\ClassMethod\\AddOverrideAttributeToOverriddenMethodsRector' => __DIR__ . '/../..' . '/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php',
'Rector\\PhpAttribute\\AnnotationToAttributeMapper' => __DIR__ . '/../..' . '/packages/PhpAttribute/AnnotationToAttributeMapper.php',
'Rector\\PhpAttribute\\AnnotationToAttributeMapper\\ArrayAnnotationToAttributeMapper' => __DIR__ . '/../..' . '/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayAnnotationToAttributeMapper.php',