From c803b81bce25dbf5f8e95fe5b33611fae925a965 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 1 Jan 2024 08:39:20 +0700 Subject: [PATCH 1/2] [Strict] Handle may be unitialized property on DisallowedEmptyRuleFixerRector --- ...tialized_property_no_default_value.php.inc | 41 +++++++++++++++++++ .../property_with_default_value.php.inc | 41 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc create mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_default_value.php.inc diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc new file mode 100644 index 00000000000..9e981ce824f --- /dev/null +++ b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc @@ -0,0 +1,41 @@ +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/property_with_default_value.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_default_value.php.inc new file mode 100644 index 00000000000..334414cd21d --- /dev/null +++ b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_default_value.php.inc @@ -0,0 +1,41 @@ +items); + } + + public function isNotEmpty() + { + return ! empty($this->items); + } +} + +?> +----- +items === []; + } + + public function isNotEmpty() + { + return $this->items !== []; + } +} + +?> From 619b849153cdec4f55509d2a683fb34f6713b70b Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 1 Jan 2024 18:52:47 +0700 Subject: [PATCH 2/2] fixed :tada: --- ...tialized_property_no_default_value.php.inc | 2 +- ...roperty_with_assign_in_constructor.php.inc | 51 ++++++++++++++ .../UnitializedPropertyAnalyzer.php | 69 +++++++++++++++++++ .../Empty_/DisallowedEmptyRuleFixerRector.php | 21 +++++- 4 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_assign_in_constructor.php.inc create mode 100644 rules/Strict/NodeAnalyzer/UnitializedPropertyAnalyzer.php diff --git a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc index 9e981ce824f..42eb3b0dc8b 100644 --- a/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc +++ b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/may_unitialized_property_no_default_value.php.inc @@ -29,7 +29,7 @@ final class MayUnitializedPropertyNoDefaultValue public function isEmpty() { - return ! isset($this->items) || $this->items === []; + return !isset($this->items) || $this->items === []; } public function isNotEmpty() 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 new file mode 100644 index 00000000000..bc42a451dbb --- /dev/null +++ b/rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector/Fixture/property_with_assign_in_constructor.php.inc @@ -0,0 +1,51 @@ +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/Strict/NodeAnalyzer/UnitializedPropertyAnalyzer.php b/rules/Strict/NodeAnalyzer/UnitializedPropertyAnalyzer.php new file mode 100644 index 00000000000..c0e8e79e80a --- /dev/null +++ b/rules/Strict/NodeAnalyzer/UnitializedPropertyAnalyzer.php @@ -0,0 +1,69 @@ +nodeTypeResolver->getType($expr->var); + + if ($varType instanceof ThisType) { + $varType = $varType->getStaticObjectType(); + } + + if (! $varType instanceof TypeWithClassName) { + return false; + } + + $className = $varType->getClassName(); + $classLike = $this->astResolver->resolveClassFromName($className); + + if (! $classLike instanceof ClassLike) { + return false; + } + + $propertyName = (string) $this->nodeNameResolver->getName($expr); + $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); + } +} diff --git a/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php b/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php index 51086fd9b83..e7b2eb3e7fe 100644 --- a/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php +++ b/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php @@ -8,12 +8,14 @@ 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\Core\Contract\Rector\ConfigurableRectorInterface; use Rector\Core\NodeAnalyzer\ExprAnalyzer; +use Rector\Strict\NodeAnalyzer\UnitializedPropertyAnalyzer; use Rector\Strict\NodeFactory\ExactCompareFactory; use Rector\Strict\Rector\AbstractFalsyScalarRuleFixerRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; @@ -26,7 +28,8 @@ final class DisallowedEmptyRuleFixerRector extends AbstractFalsyScalarRuleFixerR { public function __construct( private readonly ExactCompareFactory $exactCompareFactory, - private readonly ExprAnalyzer $exprAnalyzer + private readonly ExprAnalyzer $exprAnalyzer, + private readonly UnitializedPropertyAnalyzer $unitializedPropertyAnalyzer ) { } @@ -106,11 +109,17 @@ private function refactorBooleanNot(BooleanNot $booleanNot, Scope $scope): Expr| $emptyExprType = $scope->getNativeType($empty->expr); - return $this->exactCompareFactory->createNotIdenticalFalsyCompare( + $result = $this->exactCompareFactory->createNotIdenticalFalsyCompare( $emptyExprType, $empty->expr, $this->treatAsNonEmpty ); + + if ($this->unitializedPropertyAnalyzer->isUnitialized($empty->expr)) { + return new BooleanAnd(new Isset_([$empty->expr]), $result); + } + + return $result; } private function refactorEmpty(Empty_ $empty, Scope $scope, bool $treatAsNonEmpty): Expr|null @@ -120,7 +129,13 @@ private function refactorEmpty(Empty_ $empty, Scope $scope, bool $treatAsNonEmpt } $exprType = $scope->getNativeType($empty->expr); - return $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $empty->expr, $treatAsNonEmpty); + $result = $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $empty->expr, $treatAsNonEmpty); + + if ($this->unitializedPropertyAnalyzer->isUnitialized($empty->expr)) { + return new BooleanOr(new BooleanNot(new Isset_([$empty->expr])), $result); + } + + return $result; } private function createDimFetchBooleanAnd(ArrayDimFetch $arrayDimFetch): ?BooleanAnd