diff --git a/config/set/php83.php b/config/set/php83.php index 8e6c7ef00408..d36f3ae8256d 100644 --- a/config/set/php83.php +++ b/config/set/php83.php @@ -3,7 +3,9 @@ declare (strict_types=1); namespace RectorPrefix202312; +use Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector; +use Rector\Php83\Rector\ClassConst\AddTypeToConstRector; use Rector\Config\RectorConfig; return static function (RectorConfig $rectorConfig) : void { - $rectorConfig->rules([\Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector::class, \Rector\Php83\Rector\ClassConst\AddTypeToConstRector::class]); + $rectorConfig->rules([AddOverrideAttributeToOverriddenMethodsRector::class, AddTypeToConstRector::class]); }; diff --git a/rules/Php83/Rector/ClassConst/AddTypeToConstRector.php b/rules/Php83/Rector/ClassConst/AddTypeToConstRector.php index d6cad3b8367c..9c42dc4314de 100644 --- a/rules/Php83/Rector/ClassConst/AddTypeToConstRector.php +++ b/rules/Php83/Rector/ClassConst/AddTypeToConstRector.php @@ -3,6 +3,16 @@ declare (strict_types=1); namespace Rector\Php83\Rector\ClassConst; +use PhpParser\Node\Stmt\ClassConst; +use PhpParser\Node\Identifier; +use PhpParser\Node\Const_; +use PhpParser\Node\Expr; +use PhpParser\Node\Scalar\String_; +use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\Scalar\DNumber; +use PhpParser\Node\Expr\ConstFetch; +use PhpParser\Node\Expr\Array_; +use PhpParser\Node\Name; use PhpParser\Node; use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Stmt\Class_; @@ -18,7 +28,7 @@ /** * @see \Rector\Tests\Php83\Rector\ClassConst\AddTypeToConstRector\AddTypeToConstRectorTest */ -class AddTypeToConstRector extends AbstractRector implements MinPhpVersionInterface +final class AddTypeToConstRector extends AbstractRector implements MinPhpVersionInterface { /** * @readonly @@ -57,8 +67,8 @@ 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; + $consts = \array_filter($node->stmts, static function (Node $node) : bool { + return $node instanceof ClassConst; }); if ($consts === []) { return null; @@ -85,7 +95,7 @@ public function refactor(Node $node) : ?\PhpParser\Node\Stmt\Class_ } $valueType = $this->findValueType($constNode->value); } - if (($valueType ?? null) === null) { + if (!($valueType ?? null) instanceof Identifier) { continue; } $const->type = $valueType; @@ -105,15 +115,15 @@ public function provideMinPhpVersion() : int * @param ClassReflection[] $implementations * @param ClassReflection[] $traits */ - public function shouldSkipDueToInheritance(Node\Const_ $constNode, array $parents, array $implementations, array $traits) : bool + public function shouldSkipDueToInheritance(Const_ $const, array $parents, array $implementations, array $traits) : bool { foreach ([$parents, $implementations, $traits] as $inheritance) { foreach ($inheritance as $inheritanceItem) { - if ($constNode->name->name === '') { + if ($const->name->name === '') { continue; } try { - $inheritanceItem->getConstant($constNode->name->name); + $inheritanceItem->getConstant($const->name->name); return \true; } catch (MissingConstantFromReflectionException $exception) { } @@ -121,25 +131,25 @@ public function shouldSkipDueToInheritance(Node\Const_ $constNode, array $parent } return \false; } - private function findValueType(Node\Expr $value) : ?Node\Identifier + private function findValueType(Expr $expr) : ?Identifier { - if ($value instanceof Node\Scalar\String_) { - return new Node\Identifier('string'); + if ($expr instanceof String_) { + return new Identifier('string'); } - if ($value instanceof Node\Scalar\LNumber) { - return new Node\Identifier('int'); + if ($expr instanceof LNumber) { + return new Identifier('int'); } - if ($value instanceof Node\Scalar\DNumber) { - return new Node\Identifier('float'); + if ($expr instanceof DNumber) { + return new Identifier('float'); } - if ($value instanceof Node\Expr\ConstFetch && $value->name->toLowerString() !== 'null') { - return new Node\Identifier('bool'); + if ($expr instanceof ConstFetch && $expr->name->toLowerString() !== 'null') { + return new Identifier('bool'); } - if ($value instanceof Node\Expr\ConstFetch && $value->name->toLowerString() === 'null') { - return new Node\Identifier('null'); + if ($expr instanceof ConstFetch && $expr->name->toLowerString() === 'null') { + return new Identifier('null'); } - if ($value instanceof Node\Expr\Array_) { - return new Node\Identifier('array'); + if ($expr instanceof Array_) { + return new Identifier('array'); } return null; } @@ -149,7 +159,7 @@ private function findValueType(Node\Expr $value) : ?Node\Identifier private function getParents(Class_ $class) : array { $parents = \array_filter([$class->extends]); - return \array_map(function (Node\Name $name) : ClassReflection { + return \array_map(function (Name $name) : ClassReflection { if (!$name instanceof FullyQualified) { throw new FullyQualifiedNameNotAutoloadedException($name); } @@ -164,7 +174,7 @@ private function getParents(Class_ $class) : array */ private function getImplementations(Class_ $class) : array { - return \array_map(function (Node\Name $name) : ClassReflection { + return \array_map(function (Name $name) : ClassReflection { if (!$name instanceof FullyQualified) { throw new FullyQualifiedNameNotAutoloadedException($name); } @@ -177,13 +187,13 @@ private function getImplementations(Class_ $class) : array /** * @return ClassReflection[] */ - private function getTraits(Class_ $node) : array + private function getTraits(Class_ $class) : array { $traits = []; - foreach ($node->getTraitUses() as $traitUse) { + foreach ($class->getTraitUses() as $traitUse) { $traits = \array_merge($traits, $traitUse->traits); } - return \array_map(function (Node\Name $name) : ClassReflection { + return \array_map(function (Name $name) : ClassReflection { if (!$name instanceof FullyQualified) { throw new FullyQualifiedNameNotAutoloadedException($name); } @@ -193,8 +203,8 @@ private function getTraits(Class_ $node) : array throw new FullyQualifiedNameNotAutoloadedException($name); }, $traits); } - private function canBeInheritied(Node\Stmt\ClassConst $constNode, Class_ $node) : bool + private function canBeInheritied(ClassConst $classConst, Class_ $class) : bool { - return !$node->isFinal() && !$constNode->isPrivate(); + return !$class->isFinal() && !$classConst->isPrivate(); } } diff --git a/rules/Strict/NodeFactory/ExactCompareFactory.php b/rules/Strict/NodeFactory/ExactCompareFactory.php index 423b472e9b36..4a9dcae86560 100644 --- a/rules/Strict/NodeFactory/ExactCompareFactory.php +++ b/rules/Strict/NodeFactory/ExactCompareFactory.php @@ -34,10 +34,13 @@ public function __construct(NodeFactory $nodeFactory) /** * @return \PhpParser\Node\Expr\BinaryOp\Identical|\PhpParser\Node\Expr\BinaryOp\BooleanOr|\PhpParser\Node\Expr\BinaryOp\NotIdentical|\PhpParser\Node\Expr\BooleanNot|\PhpParser\Node\Expr\Instanceof_|\PhpParser\Node\Expr\BinaryOp\BooleanAnd|null */ - public function createIdenticalFalsyCompare(Type $exprType, Expr $expr, bool $treatAsNonEmpty) + public function createIdenticalFalsyCompare(Type $exprType, Expr $expr, bool $treatAsNonEmpty, bool $isOnlyString = \true) { if ($exprType->isString()->yes()) { - return new Identical($expr, new String_('')); + if ($treatAsNonEmpty || !$isOnlyString) { + return new Identical($expr, new String_('')); + } + return new BooleanOr(new Identical($expr, new String_('')), new Identical($expr, new String_('0'))); } if ($exprType->isInteger()->yes()) { return new Identical($expr, new LNumber(0)); @@ -54,15 +57,18 @@ public function createIdenticalFalsyCompare(Type $exprType, Expr $expr, bool $tr if (!$exprType instanceof UnionType) { return null; } - return $this->createTruthyFromUnionType($exprType, $expr, $treatAsNonEmpty); + return $this->createTruthyFromUnionType($exprType, $expr, $treatAsNonEmpty, \false); } /** * @return \PhpParser\Node\Expr\BinaryOp\Identical|\PhpParser\Node\Expr\Instanceof_|\PhpParser\Node\Expr\BinaryOp\BooleanOr|\PhpParser\Node\Expr\BinaryOp\NotIdentical|\PhpParser\Node\Expr\BinaryOp\BooleanAnd|\PhpParser\Node\Expr\BooleanNot|null */ - public function createNotIdenticalFalsyCompare(Type $exprType, Expr $expr, bool $treatAsNotEmpty) + public function createNotIdenticalFalsyCompare(Type $exprType, Expr $expr, bool $treatAsNotEmpty, bool $isOnlyString = \true) { if ($exprType->isString()->yes()) { - return new NotIdentical($expr, new String_('')); + if ($treatAsNotEmpty || !$isOnlyString) { + return new NotIdentical($expr, new String_('')); + } + return new BooleanAnd(new NotIdentical($expr, new String_('')), new NotIdentical($expr, new String_('0'))); } if ($exprType->isInteger()->yes()) { return new NotIdentical($expr, new LNumber(0)); @@ -73,12 +79,12 @@ public function createNotIdenticalFalsyCompare(Type $exprType, Expr $expr, bool if (!$exprType instanceof UnionType) { return null; } - return $this->createFromUnionType($exprType, $expr, $treatAsNotEmpty); + return $this->createFromUnionType($exprType, $expr, $treatAsNotEmpty, \false); } /** * @return \PhpParser\Node\Expr\BinaryOp\Identical|\PhpParser\Node\Expr\Instanceof_|\PhpParser\Node\Expr\BinaryOp\BooleanOr|\PhpParser\Node\Expr\BinaryOp\NotIdentical|\PhpParser\Node\Expr\BinaryOp\BooleanAnd|\PhpParser\Node\Expr\BooleanNot|null */ - private function createFromUnionType(UnionType $unionType, Expr $expr, bool $treatAsNotEmpty) + private function createFromUnionType(UnionType $unionType, Expr $expr, bool $treatAsNotEmpty, bool $isOnlyString) { $unionType = TypeCombinator::removeNull($unionType); if ($unionType->isBoolean()->yes()) { @@ -92,7 +98,7 @@ private function createFromUnionType(UnionType $unionType, Expr $expr, bool $tre if ($unionType instanceof UnionType) { return $this->resolveFromCleanedNullUnionType($unionType, $expr, $treatAsNotEmpty); } - $compareExpr = $this->createNotIdenticalFalsyCompare($unionType, $expr, $treatAsNotEmpty); + $compareExpr = $this->createNotIdenticalFalsyCompare($unionType, $expr, $treatAsNotEmpty, $isOnlyString); if (!$compareExpr instanceof Expr) { return null; } @@ -170,7 +176,7 @@ private function createBooleanAnd(array $compareExprs) /** * @return \PhpParser\Node\Expr\BinaryOp\BooleanOr|\PhpParser\Node\Expr\BinaryOp\NotIdentical|\PhpParser\Node\Expr\BinaryOp\Identical|\PhpParser\Node\Expr\BooleanNot|\PhpParser\Node\Expr\Instanceof_|\PhpParser\Node\Expr\BinaryOp\BooleanAnd|null */ - private function createTruthyFromUnionType(UnionType $unionType, Expr $expr, bool $treatAsNonEmpty) + private function createTruthyFromUnionType(UnionType $unionType, Expr $expr, bool $treatAsNonEmpty, bool $isOnlyString) { $unionType = $this->cleanUpPossibleNullableUnionType($unionType); if ($unionType instanceof UnionType) { @@ -188,7 +194,7 @@ private function createTruthyFromUnionType(UnionType $unionType, Expr $expr, boo return $toNullIdentical; } // assume we have to check empty string, integer and bools - $scalarFalsyIdentical = $this->createIdenticalFalsyCompare($unionType, $expr, $treatAsNonEmpty); + $scalarFalsyIdentical = $this->createIdenticalFalsyCompare($unionType, $expr, $treatAsNonEmpty, $isOnlyString); if (!$scalarFalsyIdentical instanceof Expr) { return null; } diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index fca245d35d8e..56085d75055c 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -19,12 +19,12 @@ final class VersionResolver * @api * @var string */ - public const PACKAGE_VERSION = 'e3f909cf030971b542c9c508298c729abb60eefe'; + public const PACKAGE_VERSION = 'd9c5d8f09bfd68e7496c07c23ddac03447cfbb32'; /** * @api * @var string */ - public const RELEASE_DATE = '2023-12-03 15:59:28'; + public const RELEASE_DATE = '2023-12-03 22:47:38'; /** * @var int */ diff --git a/src/Exception/FullyQualifiedNameNotAutoloadedException.php b/src/Exception/FullyQualifiedNameNotAutoloadedException.php index 4b73ad807ec9..47cb11d716fc 100644 --- a/src/Exception/FullyQualifiedNameNotAutoloadedException.php +++ b/src/Exception/FullyQualifiedNameNotAutoloadedException.php @@ -5,7 +5,7 @@ use PhpParser\Node\Name; use RuntimeException; -class FullyQualifiedNameNotAutoloadedException extends RuntimeException +final class FullyQualifiedNameNotAutoloadedException extends RuntimeException { /** * @var \PhpParser\Node\Name