From 36b84f18bd2669fc2d4d9ed24f7ee546d357d867 Mon Sep 17 00:00:00 2001 From: Alfred Bez Date: Wed, 14 Dec 2022 18:02:21 +0100 Subject: [PATCH 1/3] Adapt PrivateConstantToSelfRector to work on non-final classes, too --- .../docs/rector_rules_overview.md | 36 +++++- ...tantToSelfRectorForNonFinalClassesTest.php | 32 +++++ .../replace-in-private-methods.php.inc | 27 ++++ ...used-in-child-classes-as-protected.php.inc | 18 +++ ...if-used-in-child-classes-as-public.php.inc | 18 +++ ...place-if-not-used-in-child-classes.php.inc | 33 +++++ .../config/config_non_final_classes.php | 16 +++ ...nvertStaticPrivateConstantToSelfRector.php | 115 +++++++++++++++--- 8 files changed, 275 insertions(+), 20 deletions(-) create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/ConvertStaticPrivateConstantToSelfRectorForNonFinalClassesTest.php create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/Fixture/replace-in-private-methods.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-protected.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-public.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/replace-if-not-used-in-child-classes.php.inc create mode 100644 rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/config/config_non_final_classes.php diff --git a/build/target-repository/docs/rector_rules_overview.md b/build/target-repository/docs/rector_rules_overview.md index a36a1c17ca8..48194ea860f 100644 --- a/build/target-repository/docs/rector_rules_overview.md +++ b/build/target-repository/docs/rector_rules_overview.md @@ -1,4 +1,4 @@ -# 412 Rules Overview +# 413 Rules Overview
@@ -48,7 +48,7 @@ - [Php81](#php81) (11) -- [Php82](#php82) (1) +- [Php82](#php82) (2) - [Privatization](#privatization) (8) @@ -596,10 +596,25 @@ Change multiple null compares to ?? queue ### ConvertStaticPrivateConstantToSelfRector -Replaces static::* access to private constants with self::* on final classes +Replaces static::* access to private constants with self::* + +:wrench: **configure it!** - class: [`Rector\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector`](../rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php) +```php +use Rector\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector; +use Rector\Config\RectorConfig; + +return static function (RectorConfig $rectorConfig): void { + $rectorConfig->ruleWithConfiguration(ConvertStaticPrivateConstantToSelfRector::class, [ + ConvertStaticPrivateConstantToSelfRector::ENABLE_FOR_NON_FINAL_CLASSES => false, + ]); +}; +``` + +↓ + ```diff final class Foo { private const BAR = 'bar'; @@ -6511,6 +6526,21 @@ Decorate read-only class with `readonly` attribute
+### Utf8DecodeEncodeToMbConvertEncodingRector + +Change deprecated utf8_decode and utf8_encode to mb_convert_encoding + +- class: [`Rector\Php82\Rector\FuncCall\Utf8DecodeEncodeToMbConvertEncodingRector`](../rules/Php82/Rector/FuncCall/Utf8DecodeEncodeToMbConvertEncodingRector.php) + +```diff +-utf8_decode($value); +-utf8_encode($value); ++mb_convert_encoding($value, 'ISO-8859-1'); ++mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1'); +``` + +
+ ## Privatization ### ChangeGlobalVariablesToPropertiesRector diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/ConvertStaticPrivateConstantToSelfRectorForNonFinalClassesTest.php b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/ConvertStaticPrivateConstantToSelfRectorForNonFinalClassesTest.php new file mode 100644 index 00000000000..d73858d4ea0 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/ConvertStaticPrivateConstantToSelfRectorForNonFinalClassesTest.php @@ -0,0 +1,32 @@ +doTestFile($filePath); + } + + /** + * @return Iterator> + */ + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureEnableForNonFinalClasses'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/config_non_final_classes.php'; + } +} diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/Fixture/replace-in-private-methods.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/Fixture/replace-in-private-methods.php.inc new file mode 100644 index 00000000000..f7b2636e8ce --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/Fixture/replace-in-private-methods.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-protected.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-protected.php.inc new file mode 100644 index 00000000000..a254d511f01 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-protected.php.inc @@ -0,0 +1,18 @@ + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-public.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-public.php.inc new file mode 100644 index 00000000000..948655afbe8 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/do-not-replace-if-used-in-child-classes-as-public.php.inc @@ -0,0 +1,18 @@ + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/replace-if-not-used-in-child-classes.php.inc b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/replace-if-not-used-in-child-classes.php.inc new file mode 100644 index 00000000000..68075fb21f3 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/FixtureEnableForNonFinalClasses/replace-if-not-used-in-child-classes.php.inc @@ -0,0 +1,33 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/config/config_non_final_classes.php b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/config/config_non_final_classes.php new file mode 100644 index 00000000000..62d719faef2 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector/config/config_non_final_classes.php @@ -0,0 +1,16 @@ +ruleWithConfiguration( + ConvertStaticPrivateConstantToSelfRector::class, + [ + ConvertStaticPrivateConstantToSelfRector::ENABLE_FOR_NON_FINAL_CLASSES => true, + ] + ); +}; diff --git a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php index e5ec5179cf6..4f0f5e83f3d 100644 --- a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php +++ b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php @@ -9,8 +9,12 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PhpParser\Node\Stmt\Class_; +use PHPStan\Reflection\ClassReflection; +use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface; use Rector\Core\Rector\AbstractRector; -use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; +use Rector\Core\Reflection\ReflectionResolver; +use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer; +use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** @@ -18,14 +22,28 @@ * @see https://3v4l.org/8Y0ba * @see https://phpstan.org/r/11d4c850-1a40-4fae-b665-291f96104d11 */ -final class ConvertStaticPrivateConstantToSelfRector extends AbstractRector +final class ConvertStaticPrivateConstantToSelfRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface { + /** + * @api + * @var string + */ + public const ENABLE_FOR_NON_FINAL_CLASSES = 'enable_false_non_final_classes'; + + private bool $enableForNonFinalClasses = false; + + public function __construct( + private readonly FamilyRelationsAnalyzer $familyRelationsAnalyzer, + private readonly ReflectionResolver $reflectionResolver, + ) { + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( - 'Replaces static::* access to private constants with self::* on final classes', + 'Replaces static::* access to private constants with self::*', [ - new CodeSample( + new ConfiguredCodeSample( <<<'CODE_SAMPLE' final class Foo { private const BAR = 'bar'; @@ -46,6 +64,9 @@ public function run() } CODE_SAMPLE , + [ + self::ENABLE_FOR_NON_FINAL_CLASSES => false, + ], ), ], ); @@ -56,16 +77,24 @@ public function getNodeTypes(): array return [ClassConstFetch::class]; } + public function configure(array $configuration): void + { + $this->enableForNonFinalClasses = $configuration[self::ENABLE_FOR_NON_FINAL_CLASSES] ?? (bool) current( + $configuration + ); + } + /** * @param ClassConstFetch $node */ public function refactor(Node $node): ?ClassConstFetch { - if (! $this->isUsingStatic($node)) { + $class = $this->betterNodeFinder->findParentType($node, Class_::class); + if (! $class instanceof Class_) { return null; } - if (! $this->isPrivateConstant($node)) { + if ($this->shouldBeSkipped($class, $node)) { return null; } @@ -83,30 +112,82 @@ private function isUsingStatic(ClassConstFetch $classConstFetch): bool return $classConstFetch->class->toString() === 'static'; } - private function isPrivateConstant(ClassConstFetch $classConstFetch): bool + private function isPrivateConstant(ClassConstFetch $constant, Class_ $class): bool { - $class = $this->betterNodeFinder->findParentType($classConstFetch, Class_::class); - if (! $class instanceof Class_) { + $constantName = $this->getConstantName($constant); + if ($constantName === null) { return false; } + foreach ($class->getConstants() as $classConst) { + if (! $this->nodeNameResolver->isName($classConst, $constantName)) { + continue; + } + + return $classConst->isPrivate(); + } + + return false; + } + + private function isUsedInPrivateMethod(ClassConstFetch $node): bool + { + $method = $this->betterNodeFinder->findParentType($node, Node\Stmt\ClassMethod::class); - if (! $class->isFinal()) { + if (! $method instanceof Node\Stmt\ClassMethod) { return false; } - $constantName = $classConstFetch->name; - if (! $constantName instanceof Identifier) { + return $method->flags === Class_::MODIFIER_PRIVATE; + } + + private function shouldBeSkipped(Class_ $class, ClassConstFetch $classConstFetch): bool + { + if (! $this->isUsingStatic($classConstFetch)) { + return true; + } + if (! $this->isPrivateConstant($classConstFetch, $class)) { + return true; + } + if ($this->isUsedInPrivateMethod($classConstFetch)) { return false; } - foreach ($class->getConstants() as $classConst) { - if (! $this->nodeNameResolver->isName($classConst, $constantName->toString())) { - continue; - } + if ($this->enableForNonFinalClasses) { + return $this->isOverwrittenInChildClass($classConstFetch); + } - return $classConst->isPrivate(); + return ! $class->isFinal(); + } + + private function isOverwrittenInChildClass(ClassConstFetch $classConstFetch): bool + { + $constantName = $this->getConstantName($classConstFetch); + if ($constantName === null) { + return false; + } + + $classReflection = $this->reflectionResolver->resolveClassReflection($classConstFetch); + if (! $classReflection instanceof ClassReflection) { + return false; + } + $childrenClassReflections = $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection); + + foreach ($childrenClassReflections as $childrenClassReflection) { + if ($childrenClassReflection->hasConstant($constantName)) { + return true; + } } return false; } + + private function getConstantName(ClassConstFetch $classConstFetch): ?string + { + $constantNameIdentifier = $classConstFetch->name; + if (! $constantNameIdentifier instanceof Identifier) { + return null; + } + + return $constantNameIdentifier->toString(); + } } From 91ae1828bc0795b51bf44dbd8f5fa4d0f3a6eb68 Mon Sep 17 00:00:00 2001 From: Alfred Bez Date: Fri, 16 Dec 2022 08:33:39 +0100 Subject: [PATCH 2/3] Update rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php Co-authored-by: Abdul Malik Ikhsan --- .../ConvertStaticPrivateConstantToSelfRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php index 4f0f5e83f3d..b67dc0f00b6 100644 --- a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php +++ b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php @@ -28,7 +28,7 @@ final class ConvertStaticPrivateConstantToSelfRector extends AbstractRector impl * @api * @var string */ - public const ENABLE_FOR_NON_FINAL_CLASSES = 'enable_false_non_final_classes'; + public const ENABLE_FOR_NON_FINAL_CLASSES = 'enable_self_non_final_classes'; private bool $enableForNonFinalClasses = false; From d0eb498b321f623cdeb016ca0ec5b86141586456 Mon Sep 17 00:00:00 2001 From: Alfred Bez Date: Fri, 16 Dec 2022 08:37:33 +0100 Subject: [PATCH 3/3] Update rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php Co-authored-by: Abdul Malik Ikhsan --- .../ConvertStaticPrivateConstantToSelfRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php index b67dc0f00b6..ed646b104d6 100644 --- a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php +++ b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php @@ -28,7 +28,7 @@ final class ConvertStaticPrivateConstantToSelfRector extends AbstractRector impl * @api * @var string */ - public const ENABLE_FOR_NON_FINAL_CLASSES = 'enable_self_non_final_classes'; + public const ENABLE_FOR_NON_FINAL_CLASSES = 'enable_for_non_final_classes'; private bool $enableForNonFinalClasses = false;