From a3aabb97d086d86244f951e4e38a722976b19688 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 4 Aug 2026 16:09:06 +0200 Subject: [PATCH 1/2] [DeadCode] Move RemoveReadonlyPropertyVisibilityOnReadonlyClassRector to dead-code set --- src/Config/Level/CodeQualityLevel.php | 2 -- src/Config/Level/DeadCodeLevel.php | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Config/Level/CodeQualityLevel.php b/src/Config/Level/CodeQualityLevel.php index 16a1ec5b92d..2bcb9defdaa 100644 --- a/src/Config/Level/CodeQualityLevel.php +++ b/src/Config/Level/CodeQualityLevel.php @@ -20,7 +20,6 @@ use Rector\CodeQuality\Rector\Class_\ConvertStaticToSelfRector; use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector; use Rector\CodeQuality\Rector\Class_\InnerFunctionToPrivateMethodRector; -use Rector\CodeQuality\Rector\Class_\RemoveReadonlyPropertyVisibilityOnReadonlyClassRector; use Rector\CodeQuality\Rector\ClassConstFetch\VariableConstFetchToClassConstFetchRector; use Rector\CodeQuality\Rector\ClassMethod\ExplicitReturnNullRector; use Rector\CodeQuality\Rector\ClassMethod\InlineArrayReturnAssignRector; @@ -169,7 +168,6 @@ final class CodeQualityLevel ConvertStaticToSelfRector::class, SortCallLikeNamedArgsRector::class, SortAttributeNamedArgsRector::class, - RemoveReadonlyPropertyVisibilityOnReadonlyClassRector::class, SafeDeclareStrictTypesRector::class, ]; diff --git a/src/Config/Level/DeadCodeLevel.php b/src/Config/Level/DeadCodeLevel.php index 0e19d559546..81cded04455 100644 --- a/src/Config/Level/DeadCodeLevel.php +++ b/src/Config/Level/DeadCodeLevel.php @@ -4,6 +4,7 @@ namespace Rector\Config\Level; +use Rector\CodeQuality\Rector\Class_\RemoveReadonlyPropertyVisibilityOnReadonlyClassRector; use Rector\CodeQuality\Rector\FuncCall\UnwrapSprintfOneArgumentRector; use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector; use Rector\CodeQuality\Rector\Identical\SimplifyBoolIdenticalTrueRector; @@ -114,6 +115,7 @@ final class DeadCodeLevel RemoveFinalFromConstRector::class, UnwrapSprintfOneArgumentRector::class, SimplifyBoolIdenticalTrueRector::class, + RemoveReadonlyPropertyVisibilityOnReadonlyClassRector::class, RemoveTypedPropertyDeadInstanceOfRector::class, RemoveDeadInstanceOfAssertRector::class, From 65d822d9d09e010ffd3f4bcbd1a3b8361c88bfab Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 4 Aug 2026 16:12:53 +0200 Subject: [PATCH 2/2] [Strict] Deprecate DisallowedEmptyRuleFixerRector The rule turns empty() into long isset()/comparison chains that are harder to read than the original. Refactoring the value to a single sole type is the better fix. --- .../DisallowedEmptyRuleFixerRectorTest.php | 28 -- .../Fixture/empty_string_nullable.php.inc | 27 -- .../Fixture/from_return_method.php.inc | 47 --- ...tialized_property_no_default_value.php.inc | 41 --- ...d_static_property_no_default_value.php.inc | 41 --- .../Fixture/negated_empty_array.php.inc | 27 -- .../negation_empty_string_nullable.php.inc | 27 -- .../Fixture/nullable_bool.php.inc | 27 -- ...roperty_with_assign_in_constructor.php.inc | 51 --- .../property_with_default_value.php.inc | 41 --- ...rray_dim_fetch_from_property_fetch.php.inc | 19 -- ...m_fetch_from_static_property_fetch.php.inc | 19 -- .../Fixture/skip_empty_from_param_doc.php.inc | 16 - .../Fixture/skip_from_docblock_return.php.inc | 23 -- .../skip_multi_union_types_from_docs.php.inc | 14 - .../skip_negated_union_types_from_doc.php.inc | 14 - .../Fixture/skip_untyped_property.php.inc | 18 - .../Fixture/some_empty_array.php.inc | 27 -- .../Fixture/union_object_nullable.php.inc | 27 -- .../config/configured_rule.php | 9 - .../UninitializedPropertyAnalyzer.php | 98 ------ .../NodeFactory/ExactCompareFactory.php | 319 ------------------ .../AbstractFalsyScalarRuleFixerRector.php | 34 -- .../Empty_/DisallowedEmptyRuleFixerRector.php | 117 ++----- src/Config/Level/CodeQualityLevel.php | 2 - .../SimplifyEmpty/Fixture/fixture.php.inc | 61 ---- .../SimplifyEmpty/SimplifyEmptyTest.php | 28 -- .../SimplifyEmpty/config/configured_rule.php | 13 - 28 files changed, 20 insertions(+), 1195 deletions(-) delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/DisallowedEmptyRuleFixerRectorTest.php delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/empty_string_nullable.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/from_return_method.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_property_no_default_value.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_static_property_no_default_value.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negated_empty_array.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negation_empty_string_nullable.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/nullable_bool.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_assign_in_constructor.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_default_value.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_property_fetch.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_static_property_fetch.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_empty_from_param_doc.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_from_docblock_return.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_multi_union_types_from_docs.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_negated_union_types_from_doc.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_untyped_property.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/some_empty_array.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/union_object_nullable.php.inc delete mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/config/configured_rule.php delete mode 100644 rules/Strict/NodeAnalyzer/UninitializedPropertyAnalyzer.php delete mode 100644 rules/Strict/NodeFactory/ExactCompareFactory.php delete mode 100644 rules/Strict/Rector/AbstractFalsyScalarRuleFixerRector.php delete mode 100644 tests/Issues/SimplifyEmpty/Fixture/fixture.php.inc delete mode 100644 tests/Issues/SimplifyEmpty/SimplifyEmptyTest.php delete mode 100644 tests/Issues/SimplifyEmpty/config/configured_rule.php diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/DisallowedEmptyRuleFixerRectorTest.php b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/DisallowedEmptyRuleFixerRectorTest.php deleted file mode 100644 index 53dadc79bd2..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/DisallowedEmptyRuleFixerRectorTest.php +++ /dev/null @@ -1,28 +0,0 @@ -doTestFile($filePath); - } - - public static function provideData(): Iterator - { - return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); - } - - public function provideConfigFilePath(): string - { - return __DIR__ . '/config/configured_rule.php'; - } -} diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/empty_string_nullable.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/empty_string_nullable.php.inc deleted file mode 100644 index 91cf79b8dd0..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/empty_string_nullable.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/from_return_method.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/from_return_method.php.inc deleted file mode 100644 index 9db99b55af6..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/from_return_method.php.inc +++ /dev/null @@ -1,47 +0,0 @@ -getProperty()); - } - - public function run2() - { - return ! empty($this->getProperty()); - } - - public function getProperty(): string - { - return ''; - } -} - -?> ------ -getProperty(), ['', '0'], true); - } - - public function run2() - { - return !in_array($this->getProperty(), ['', '0'], true); - } - - public function getProperty(): string - { - return ''; - } -} - -?> diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_property_no_default_value.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_property_no_default_value.php.inc deleted file mode 100644 index 8a9b065ad96..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_property_no_default_value.php.inc +++ /dev/null @@ -1,41 +0,0 @@ -items); - } - - public function isNotEmpty() - { - return ! empty($this->items); - } -} - -?> ------ -items) || $this->items === []; - } - - public function isNotEmpty() - { - return isset($this->items) && $this->items !== []; - } -} - -?> diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_static_property_no_default_value.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_static_property_no_default_value.php.inc deleted file mode 100644 index 214d7b9909c..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_uninitialized_static_property_no_default_value.php.inc +++ /dev/null @@ -1,41 +0,0 @@ - ------ - diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negated_empty_array.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negated_empty_array.php.inc deleted file mode 100644 index 0b24045da75..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negated_empty_array.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negation_empty_string_nullable.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negation_empty_string_nullable.php.inc deleted file mode 100644 index 81e067fc40e..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/negation_empty_string_nullable.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/nullable_bool.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/nullable_bool.php.inc deleted file mode 100644 index bcfe8ea38f3..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/nullable_bool.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_assign_in_constructor.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_assign_in_constructor.php.inc deleted file mode 100644 index bc42a451dbb..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_assign_in_constructor.php.inc +++ /dev/null @@ -1,51 +0,0 @@ -items = []; - } - - public function isEmpty() - { - return empty($this->items); - } - - public function isNotEmpty() - { - return ! empty($this->items); - } -} - -?> ------ -items = []; - } - - public function isEmpty() - { - return $this->items === []; - } - - public function isNotEmpty() - { - return $this->items !== []; - } -} - -?> diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_default_value.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_default_value.php.inc deleted file mode 100644 index 334414cd21d..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_default_value.php.inc +++ /dev/null @@ -1,41 +0,0 @@ -items); - } - - public function isNotEmpty() - { - return ! empty($this->items); - } -} - -?> ------ -items === []; - } - - public function isNotEmpty() - { - return $this->items !== []; - } -} - -?> diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_property_fetch.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_property_fetch.php.inc deleted file mode 100644 index 6cce8cd69e9..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_property_fetch.php.inc +++ /dev/null @@ -1,19 +0,0 @@ - - */ - protected array $labels = []; - - public function getLabel(string $value): string - { - if (empty($this->labels[$value])) { - throw new \InvalidArgumentException(sprintf('%s is missing label for value "%s"', static::class, $value)); - } - - return $this->labels[$value]; - } -} diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_static_property_fetch.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_static_property_fetch.php.inc deleted file mode 100644 index 855de842375..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_arg_array_dim_fetch_from_static_property_fetch.php.inc +++ /dev/null @@ -1,19 +0,0 @@ - - */ - protected static array $labels = []; - - public static function getLabel(string $value): string - { - if (empty(static::$labels[$value])) { - throw new \InvalidArgumentException(sprintf('%s is missing label for value "%s"', static::class, $value)); - } - - return static::$labels[$value]; - } -} diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_empty_from_param_doc.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_empty_from_param_doc.php.inc deleted file mode 100644 index ccbcb021e13..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_empty_from_param_doc.php.inc +++ /dev/null @@ -1,16 +0,0 @@ -getProperty()); - } - - public function run2() - { - return ! empty($this->getProperty()); - } - - /** - * @return string - */ - public function getProperty() - { - } -} diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_multi_union_types_from_docs.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_multi_union_types_from_docs.php.inc deleted file mode 100644 index 5183bf50816..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/skip_multi_union_types_from_docs.php.inc +++ /dev/null @@ -1,14 +0,0 @@ -items); - } - - public function isNotEmpty() - { - return ! empty($this->items); - } -} diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/some_empty_array.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/some_empty_array.php.inc deleted file mode 100644 index 1127a654c4a..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/some_empty_array.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/union_object_nullable.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/union_object_nullable.php.inc deleted file mode 100644 index 762e36fbe49..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/union_object_nullable.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/config/configured_rule.php b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/config/configured_rule.php deleted file mode 100644 index a230bbec5b5..00000000000 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/config/configured_rule.php +++ /dev/null @@ -1,9 +0,0 @@ -withRules([DisallowedEmptyRuleFixerRector::class]); diff --git a/rules/Strict/NodeAnalyzer/UninitializedPropertyAnalyzer.php b/rules/Strict/NodeAnalyzer/UninitializedPropertyAnalyzer.php deleted file mode 100644 index b73d90c5f3b..00000000000 --- a/rules/Strict/NodeAnalyzer/UninitializedPropertyAnalyzer.php +++ /dev/null @@ -1,98 +0,0 @@ -nodeTypeResolver->getType($expr->var) - : $this->nodeTypeResolver->getType($expr->class); - - if ($varType instanceof ThisType) { - $varType = $varType->getStaticObjectType(); - } - - $className = ClassNameFromObjectTypeResolver::resolve($varType); - if ($className === null) { - return false; - } - - $propertyName = (string) $this->nodeNameResolver->getName($expr); - - // fast-path: a typed property with an explicit default is always initialized, - // so we can skip the heavy class parsing below - if ($this->hasTypedDefaultProperty($className, $propertyName)) { - return false; - } - - $classLike = $this->astResolver->resolveClassFromName($className); - - if (! $classLike instanceof ClassLike) { - return false; - } - - $property = $classLike->getProperty($propertyName); - - if (! $property instanceof Property) { - return false; - } - - if (count($property->props) !== 1) { - return false; - } - - if ($property->props[0]->default instanceof Expr) { - return false; - } - - return ! $this->constructorAssignDetector->isPropertyAssigned($classLike, $propertyName); - } - - private function hasTypedDefaultProperty(string $className, string $propertyName): bool - { - if (! $this->reflectionProvider->hasClass($className)) { - return false; - } - - $classReflection = $this->reflectionProvider->getClass($className); - if (! $classReflection->hasNativeProperty($propertyName)) { - return false; - } - - $nativeReflectionProperty = $classReflection->getNativeProperty($propertyName) - ->getNativeReflection(); - - // an untyped property has an implicit null default, which is not an explicit initialization - return $nativeReflectionProperty->hasType() && $nativeReflectionProperty->hasDefaultValue(); - } -} diff --git a/rules/Strict/NodeFactory/ExactCompareFactory.php b/rules/Strict/NodeFactory/ExactCompareFactory.php deleted file mode 100644 index 3d1205d5a99..00000000000 --- a/rules/Strict/NodeFactory/ExactCompareFactory.php +++ /dev/null @@ -1,319 +0,0 @@ -isString()->yes()) { - if ($treatAsNonEmpty || ! $isOnlyString) { - return new Identical($expr, new String_('')); - } - - $result = new BooleanOr(new Identical($expr, new String_('')), new Identical($expr, new String_('0'))); - } elseif ($exprType->isInteger()->yes()) { - return new Identical($expr, new Int_(0)); - } elseif ($exprType->isBoolean()->yes()) { - return new Identical($expr, $this->nodeFactory->createFalse()); - } elseif ($exprType->isArray()->yes()) { - return new Identical($expr, new Array_([])); - } elseif ($exprType->isNull()->yes()) { - return new Identical($expr, $this->nodeFactory->createNull()); - } elseif (! $exprType instanceof UnionType) { - return null; - } else { - $result = $this->createTruthyFromUnionType($exprType, $expr, $treatAsNonEmpty, false); - } - - if ($result instanceof BooleanOr && $expr instanceof CallLike && $result->left instanceof Identical && $result->right instanceof Identical) { - return new FuncCall(new Name('in_array'), [ - new Arg($expr), - new Arg(new Array_([new ArrayItem($result->left->right), new ArrayItem($result->right->right)])), - new Arg(new ConstFetch(new Name('true'))), - ]); - } - - if ($result instanceof BooleanOr - && $expr instanceof CallLike - && $result->left instanceof BooleanOr - && $result->left->left instanceof Identical - && $result->left->right instanceof Identical - && $result->right instanceof Identical) { - return new FuncCall(new Name('in_array'), [ - new Arg($expr), - new Arg(new Array_([ - new ArrayItem($result->left->left->right), - new ArrayItem($result->left->right->right), - new ArrayItem($result->right->right), - ])), - new Arg(new ConstFetch(new Name('true'))), - ]); - } - - return $result; - } - - public function createNotIdenticalFalsyCompare( - Type $exprType, - Expr $expr, - bool $treatAsNotEmpty, - bool $isOnlyString = true - ): Identical|Instanceof_|NotIdentical|BooleanAnd|BooleanNot|null { - $result = null; - - if ($exprType->isString()->yes()) { - if ($treatAsNotEmpty || ! $isOnlyString) { - return new NotIdentical($expr, new String_('')); - } - - $result = new BooleanAnd( - new NotIdentical($expr, new String_('')), - new NotIdentical($expr, new String_('0')) - ); - } elseif ($exprType->isInteger()->yes()) { - return new NotIdentical($expr, new Int_(0)); - } elseif ($exprType->isArray()->yes()) { - return new NotIdentical($expr, new Array_([])); - } elseif (! $exprType instanceof UnionType) { - return null; - } else { - $result = $this->createFromUnionType($exprType, $expr, $treatAsNotEmpty, false); - } - - if ($result instanceof BooleanAnd && $expr instanceof CallLike && $result->left instanceof NotIdentical && $result->right instanceof NotIdentical) { - return new BooleanNot(new FuncCall(new Name('in_array'), [ - new Arg($expr), - new Arg(new Array_([new ArrayItem($result->left->right), new ArrayItem($result->right->right)])), - new Arg(new ConstFetch(new Name('true'))), - ])); - } - - if ($result instanceof BooleanAnd - && $expr instanceof CallLike - && $result->left instanceof BooleanAnd - && $result->left->left instanceof NotIdentical - && $result->left->right instanceof NotIdentical - && $result->right instanceof NotIdentical) { - return new BooleanNot(new FuncCall(new Name('in_array'), [ - new Arg($expr), - new Arg(new Array_([ - new ArrayItem($result->left->left->right), - new ArrayItem($result->left->right->right), - new ArrayItem($result->right->right), - ])), - new Arg(new ConstFetch(new Name('true'))), - ])); - } - - return $result; - } - - private function createFromUnionType( - UnionType $unionType, - Expr $expr, - bool $treatAsNotEmpty, - bool $isOnlyString - ): Identical|Instanceof_|BooleanAnd|null { - $unionType = TypeCombinator::removeNull($unionType); - - if ($unionType->isBoolean()->yes()) { - return new Identical($expr, $this->nodeFactory->createTrue()); - } - - $className = ClassNameFromObjectTypeResolver::resolve($unionType); - if ($className !== null) { - return new Instanceof_($expr, new FullyQualified($className)); - } - - $nullConstFetch = $this->nodeFactory->createNull(); - $toNullNotIdentical = new NotIdentical($expr, $nullConstFetch); - - if ($unionType instanceof UnionType) { - return $this->resolveFromCleanedNullUnionType($unionType, $expr, $treatAsNotEmpty); - } - - $compareExpr = $this->createNotIdenticalFalsyCompare($unionType, $expr, $treatAsNotEmpty, $isOnlyString); - if (! $compareExpr instanceof Expr) { - return null; - } - - if ($treatAsNotEmpty) { - return new BooleanAnd($toNullNotIdentical, $compareExpr); - } - - if ($unionType->isString()->yes()) { - $booleanAnd = new BooleanAnd($toNullNotIdentical, $compareExpr); - - return new BooleanAnd($booleanAnd, new NotIdentical($expr, new String_('0'))); - } - - return new BooleanAnd($toNullNotIdentical, $compareExpr); - } - - private function resolveFromCleanedNullUnionType( - UnionType $unionType, - Expr $expr, - bool $treatAsNotEmpty - ): ?BooleanAnd { - $compareExprs = $this->collectCompareExprs($unionType, $expr, $treatAsNotEmpty, false); - return $this->createBooleanAnd($compareExprs); - } - - /** - * @return array - */ - private function collectCompareExprs( - UnionType $unionType, - Expr $expr, - bool $treatAsNonEmpty, - bool $identical = true - ): array { - $compareExprs = []; - foreach ($unionType->getTypes() as $unionedType) { - $compareExprs[] = $identical - ? $this->createIdenticalFalsyCompare($unionedType, $expr, $treatAsNonEmpty) - : $this->createNotIdenticalFalsyCompare($unionedType, $expr, $treatAsNonEmpty); - } - - return array_unique($compareExprs, SORT_REGULAR); - } - - private function cleanUpPossibleNullableUnionType(UnionType $unionType): Type - { - return count($unionType->getTypes()) === 2 - ? TypeCombinator::removeNull($unionType) - : $unionType; - } - - /** - * @param array $compareExprs - */ - private function createBooleanOr(array $compareExprs): ?BooleanOr - { - $truthyExpr = array_shift($compareExprs); - - foreach ($compareExprs as $compareExpr) { - if (! $compareExpr instanceof Expr) { - return null; - } - - if (! $truthyExpr instanceof Expr) { - return null; - } - - $truthyExpr = new BooleanOr($truthyExpr, $compareExpr); - } - - if (! $truthyExpr instanceof BooleanOr) { - return null; - } - - return $truthyExpr; - } - - /** - * @param array $compareExprs - */ - private function createBooleanAnd(array $compareExprs): ?BooleanAnd - { - $truthyExpr = array_shift($compareExprs); - - foreach ($compareExprs as $compareExpr) { - if (! $compareExpr instanceof Expr) { - return null; - } - - if (! $truthyExpr instanceof Expr) { - return null; - } - - $truthyExpr = new BooleanAnd($truthyExpr, $compareExpr); - } - - if (! $truthyExpr instanceof BooleanAnd) { - return null; - } - - return $truthyExpr; - } - - private function createTruthyFromUnionType( - UnionType $unionType, - Expr $expr, - bool $treatAsNonEmpty, - bool $isOnlyString - ): BooleanOr|NotIdentical|Identical|BooleanNot|null { - $unionType = $this->cleanUpPossibleNullableUnionType($unionType); - - if ($unionType instanceof UnionType) { - $compareExprs = $this->collectCompareExprs($unionType, $expr, $treatAsNonEmpty); - return $this->createBooleanOr($compareExprs); - } - - if ($unionType->isBoolean()->yes()) { - return new NotIdentical($expr, $this->nodeFactory->createTrue()); - } - - $className = ClassNameFromObjectTypeResolver::resolve($unionType); - if ($className !== null) { - return new BooleanNot(new Instanceof_($expr, new FullyQualified($className))); - } - - $toNullIdentical = new Identical($expr, $this->nodeFactory->createNull()); - - if ($treatAsNonEmpty) { - return $toNullIdentical; - } - - // assume we have to check empty string, integer and bools - $scalarFalsyIdentical = $this->createIdenticalFalsyCompare($unionType, $expr, $treatAsNonEmpty, $isOnlyString); - if (! $scalarFalsyIdentical instanceof Expr) { - return null; - } - - if ($unionType->isString()->yes()) { - $booleanOr = new BooleanOr($toNullIdentical, $scalarFalsyIdentical); - - return new BooleanOr($booleanOr, new Identical($expr, new String_('0'))); - } - - return new BooleanOr($toNullIdentical, $scalarFalsyIdentical); - } -} diff --git a/rules/Strict/Rector/AbstractFalsyScalarRuleFixerRector.php b/rules/Strict/Rector/AbstractFalsyScalarRuleFixerRector.php deleted file mode 100644 index ac4f08572c1..00000000000 --- a/rules/Strict/Rector/AbstractFalsyScalarRuleFixerRector.php +++ /dev/null @@ -1,34 +0,0 @@ - $configuration - */ - public function configure(array $configuration): void - { - $treatAsNonEmpty = $configuration[self::TREAT_AS_NON_EMPTY] ?? (bool) current($configuration); - Assert::boolean($treatAsNonEmpty); - - $this->treatAsNonEmpty = $treatAsNonEmpty; - } -} diff --git a/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php b/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php index 4df8fdb9f21..834a50ce5f7 100644 --- a/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php +++ b/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php @@ -5,33 +5,30 @@ namespace Rector\Strict\Rector\Empty_; use PhpParser\Node; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\BinaryOp\BooleanAnd; -use PhpParser\Node\Expr\BinaryOp\BooleanOr; use PhpParser\Node\Expr\BooleanNot; use PhpParser\Node\Expr\Empty_; -use PhpParser\Node\Expr\Isset_; -use PHPStan\Analyser\Scope; +use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; use Rector\Contract\Rector\ConfigurableRectorInterface; -use Rector\NodeAnalyzer\ExprAnalyzer; -use Rector\PHPStan\ScopeFetcher; -use Rector\Strict\NodeAnalyzer\UninitializedPropertyAnalyzer; -use Rector\Strict\NodeFactory\ExactCompareFactory; -use Rector\Strict\Rector\AbstractFalsyScalarRuleFixerRector; +use Rector\Exception\ShouldNotHappenException; +use Rector\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\DisallowedEmptyRuleFixerRectorTest + * @deprecated This rule is deprecated, as it creates unreadable code with messy isset()/comparison checks. Refactor the value to a single sole type instead, then the empty() check can be replaced by a clear comparison. */ -final class DisallowedEmptyRuleFixerRector extends AbstractFalsyScalarRuleFixerRector implements ConfigurableRectorInterface +final class DisallowedEmptyRuleFixerRector extends AbstractRector implements ConfigurableRectorInterface, DeprecatedInterface { - public function __construct( - private readonly ExactCompareFactory $exactCompareFactory, - private readonly ExprAnalyzer $exprAnalyzer, - private readonly UninitializedPropertyAnalyzer $uninitializedPropertyAnalyzer - ) { + /** + * @api + */ + public const string TREAT_AS_NON_EMPTY = 'treat_as_non_empty'; + + /** + * @param array $configuration + */ + public function configure(array $configuration): void + { } public function getRuleDefinition(): RuleDefinition @@ -76,85 +73,11 @@ public function getNodeTypes(): array /** * @param Empty_|BooleanNot $node */ - public function refactor(Node $node): Expr|null - { - $scope = ScopeFetcher::fetch($node); - - if ($node instanceof BooleanNot) { - return $this->refactorBooleanNot($node, $scope); - } - - if ($node->expr instanceof ArrayDimFetch) { - return null; - } - - return $this->refactorEmpty($node, $scope, $this->treatAsNonEmpty); - } - - private function refactorBooleanNot(BooleanNot $booleanNot, Scope $scope): Expr|null + public function refactor(Node $node): ?Node { - if (! $booleanNot->expr instanceof Empty_) { - return null; - } - - $empty = $booleanNot->expr; - if ($empty->expr instanceof ArrayDimFetch) { - return $this->createDimFetchBooleanAnd($empty->expr); - } - - if ($this->exprAnalyzer->isNonTypedFromParam($empty->expr)) { - return null; - } - - $emptyExprType = $scope->getNativeType($empty->expr); - - $result = $this->exactCompareFactory->createNotIdenticalFalsyCompare( - $emptyExprType, - $empty->expr, - $this->treatAsNonEmpty - ); - - if (! $result instanceof Expr) { - return null; - } - - if ($this->uninitializedPropertyAnalyzer->isUninitialized($empty->expr)) { - return new BooleanAnd(new Isset_([$empty->expr]), $result); - } - - return $result; - } - - private function refactorEmpty(Empty_ $empty, Scope $scope, bool $treatAsNonEmpty): Expr|null - { - if ($this->exprAnalyzer->isNonTypedFromParam($empty->expr)) { - return null; - } - - $exprType = $scope->getNativeType($empty->expr); - $result = $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $empty->expr, $treatAsNonEmpty); - if (! $result instanceof Expr) { - return null; - } - - if ($this->uninitializedPropertyAnalyzer->isUninitialized($empty->expr)) { - return new BooleanOr(new BooleanNot(new Isset_([$empty->expr])), $result); - } - - return $result; - } - - private function createDimFetchBooleanAnd(ArrayDimFetch $arrayDimFetch): ?BooleanAnd - { - $exprType = $this->nodeTypeResolver->getNativeType($arrayDimFetch); - - $isset = new Isset_([$arrayDimFetch]); - $compareExpr = $this->exactCompareFactory->createNotIdenticalFalsyCompare($exprType, $arrayDimFetch, false); - - if (! $compareExpr instanceof Expr) { - return null; - } - - return new BooleanAnd($isset, $compareExpr); + throw new ShouldNotHappenException(sprintf( + '"%s" rule is deprecated, as it creates unreadable code with messy checks; refactor the value to a sole type instead', + self::class + )); } } diff --git a/src/Config/Level/CodeQualityLevel.php b/src/Config/Level/CodeQualityLevel.php index 2bcb9defdaa..b41752b838a 100644 --- a/src/Config/Level/CodeQualityLevel.php +++ b/src/Config/Level/CodeQualityLevel.php @@ -75,7 +75,6 @@ use Rector\Php52\Rector\Property\VarToPublicPropertyRector; use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; use Rector\Renaming\Rector\FuncCall\RenameFunctionRector; -use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector; use Rector\TypeDeclaration\Rector\StmtsAwareInterface\SafeDeclareStrictTypesRector; /** @@ -161,7 +160,6 @@ final class CodeQualityLevel OptionalParametersAfterRequiredRector::class, SimplifyEmptyCheckOnEmptyArrayRector::class, CleanupUnneededNullsafeOperatorRector::class, - DisallowedEmptyRuleFixerRector::class, LocallyCalledStaticMethodToNonStaticRector::class, NumberCompareToMaxFuncCallRector::class, RemoveUselessIsObjectCheckRector::class, diff --git a/tests/Issues/SimplifyEmpty/Fixture/fixture.php.inc b/tests/Issues/SimplifyEmpty/Fixture/fixture.php.inc deleted file mode 100644 index eed7ea51454..00000000000 --- a/tests/Issues/SimplifyEmpty/Fixture/fixture.php.inc +++ /dev/null @@ -1,61 +0,0 @@ -string; - } - - public function getString2(): ?string - { - return $this->string2; - } - - public function check(): bool - { - if (empty($this->getString()) || (empty($this->getString2()) && !is_numeric($this->getString2()))) { - return false; - } - - return true; - } -} - -?> ------ -string; - } - - public function getString2(): ?string - { - return $this->string2; - } - - public function check(): bool - { - return !in_array($this->getString(), [null, '', '0'], true) && !(in_array($this->getString2(), [null, '', '0'], true) && !is_numeric($this->getString2())); - } -} - -?> diff --git a/tests/Issues/SimplifyEmpty/SimplifyEmptyTest.php b/tests/Issues/SimplifyEmpty/SimplifyEmptyTest.php deleted file mode 100644 index 7c81bc83a0b..00000000000 --- a/tests/Issues/SimplifyEmpty/SimplifyEmptyTest.php +++ /dev/null @@ -1,28 +0,0 @@ -doTestFile($filePath); - } - - public static function provideData(): Iterator - { - return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); - } - - public function provideConfigFilePath(): string - { - return __DIR__ . '/config/configured_rule.php'; - } -} diff --git a/tests/Issues/SimplifyEmpty/config/configured_rule.php b/tests/Issues/SimplifyEmpty/config/configured_rule.php deleted file mode 100644 index 5b3d54394a5..00000000000 --- a/tests/Issues/SimplifyEmpty/config/configured_rule.php +++ /dev/null @@ -1,13 +0,0 @@ -withRules( - [SimplifyIfReturnBoolRector::class, SimplifyDeMorganBinaryRector::class, DisallowedEmptyRuleFixerRector::class] - );