From 8c31bd27e43a3122ab0b01e24b9d256a22e5496d Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 27 Jul 2020 15:40:30 +0200 Subject: [PATCH] [CodeQuality] Add case class name fix --- config/set/code-quality.php | 3 + docs/rector_rules_overview.md | 28 +++- rector-ci.php | 3 + .../FixClassCaseSensitivityNameRector.php | 143 ++++++++++++++++++ .../FixClassCaseSensitivityNameRectorTest.php | 34 +++++ .../Fixture/fixture.php.inc | 31 ++++ .../Fixture/namespace_and_constants.php.inc | 31 ++++ .../Fixture/param_type.php.inc | 31 ++++ .../Fixture/skip_self_parent.php.inc | 11 ++ .../Fixture/skip_short_import.php.inc | 13 ++ .../Source/MissCaseTypedClass.php | 13 ++ 11 files changed, 339 insertions(+), 2 deletions(-) create mode 100644 rules/code-quality/src/Rector/Name/FixClassCaseSensitivityNameRector.php create mode 100644 rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/FixClassCaseSensitivityNameRectorTest.php create mode 100644 rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/fixture.php.inc create mode 100644 rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/namespace_and_constants.php.inc create mode 100644 rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/param_type.php.inc create mode 100644 rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/skip_self_parent.php.inc create mode 100644 rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/skip_short_import.php.inc create mode 100644 rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Source/MissCaseTypedClass.php diff --git a/config/set/code-quality.php b/config/set/code-quality.php index 801275953d4..0cdbe1eff09 100644 --- a/config/set/code-quality.php +++ b/config/set/code-quality.php @@ -53,6 +53,7 @@ use Rector\CodeQuality\Rector\If_\SimplifyIfNotNullReturnRector; use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector; use Rector\CodeQuality\Rector\Include_\AbsolutizeRequireAndIncludePathRector; use Rector\CodeQuality\Rector\LogicalAnd\AndAssignsToSeparateLinesRector; +use Rector\CodeQuality\Rector\Name\FixClassCaseSensitivityNameRector; use Rector\CodeQuality\Rector\NotEqual\CommonNotEqualRector; use Rector\CodeQuality\Rector\Return_\SimplifyUselessVariableRector; use Rector\CodeQuality\Rector\Ternary\ArrayKeyExistsTernaryThenValueToCoalescingRector; @@ -214,4 +215,6 @@ return static function (ContainerConfigurator $containerConfigurator): void { $services->set(LogicalToBooleanRector::class); $services->set(VarToPublicPropertyRector::class); + + $services->set(FixClassCaseSensitivityNameRector::class); }; diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md index de98d35aa22..70035b3c43e 100644 --- a/docs/rector_rules_overview.md +++ b/docs/rector_rules_overview.md @@ -1,4 +1,4 @@ -# All 536 Rectors Overview +# All 537 Rectors Overview - [Projects](#projects) - [General](#general) @@ -9,7 +9,7 @@ - [Architecture](#architecture) (4) - [Autodiscovery](#autodiscovery) (4) - [CakePHP](#cakephp) (6) -- [CodeQuality](#codequality) (57) +- [CodeQuality](#codequality) (58) - [CodingStyle](#codingstyle) (36) - [DeadCode](#deadcode) (40) - [Decomplex](#decomplex) (1) @@ -814,6 +814,30 @@ Make if conditions more explicit

+### `FixClassCaseSensitivityNameRector` + +- class: [`Rector\CodeQuality\Rector\Name\FixClassCaseSensitivityNameRector`](/../master/rules/code-quality/src/Rector/Name/FixClassCaseSensitivityNameRector.php) +- [test fixtures](/../master/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture) + +Change miss-typed case sensitivity name to correct one + +```diff + final class SomeClass + { + public function run() + { +- $anotherClass = new anotherclass; ++ $anotherClass = new AnotherClass; + } + } + + final class AnotherClass + { + } +``` + +

+ ### `ForRepeatedCountToOwnVariableRector` - class: [`Rector\CodeQuality\Rector\For_\ForRepeatedCountToOwnVariableRector`](/../master/rules/code-quality/src/Rector/For_/ForRepeatedCountToOwnVariableRector.php) diff --git a/rector-ci.php b/rector-ci.php index 113fd6a096b..9184ce1d423 100644 --- a/rector-ci.php +++ b/rector-ci.php @@ -9,6 +9,7 @@ use Rector\Core\Configuration\Option; use Rector\DeadCode\Rector\ClassConst\RemoveUnusedClassConstantRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Set\ValueObject\SetList; +use Rector\SymfonyPhpConfig\Rector\Closure\AddEmptyLineBetweenCallsInPhpConfigRector; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $containerConfigurator): void { @@ -19,6 +20,8 @@ return static function (ContainerConfigurator $containerConfigurator): void { TestCase::class => ['provideData', 'provideData*', 'dataProvider', 'dataProvider*'], ]); + $services->set(AddEmptyLineBetweenCallsInPhpConfigRector::class); + $parameters = $containerConfigurator->parameters(); $parameters->set(Option::SETS, [ diff --git a/rules/code-quality/src/Rector/Name/FixClassCaseSensitivityNameRector.php b/rules/code-quality/src/Rector/Name/FixClassCaseSensitivityNameRector.php new file mode 100644 index 00000000000..26639b42519 --- /dev/null +++ b/rules/code-quality/src/Rector/Name/FixClassCaseSensitivityNameRector.php @@ -0,0 +1,143 @@ +reflectionProvider = $reflectionProvider; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Change miss-typed case sensitivity name to correct one', [ + new CodeSample( + <<<'PHP' +final class SomeClass +{ + public function run() + { + $anotherClass = new anotherclass; + } +} + +final class AnotherClass +{ +} +PHP +, + <<<'PHP' +final class SomeClass +{ + public function run() + { + $anotherClass = new AnotherClass; + } +} + +final class AnotherClass +{ +} +PHP + + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [Name::class]; + } + + /** + * @param Name $node + */ + public function refactor(Node $node): ?Node + { + $fullyQualifiedName = $this->resolveFullyQualifiedName($node); + if ($fullyQualifiedName === null) { + return null; + } + + if (! $this->reflectionProvider->hasClass($fullyQualifiedName)) { + return null; + } + + $classReflection = $this->reflectionProvider->getClass($fullyQualifiedName); + if ($classReflection->isBuiltin()) { + // skip built-in classes + return null; + } + + $realClassName = $classReflection->getName(); + if (strtolower($realClassName) !== strtolower($fullyQualifiedName)) { + // skip class alias + return null; + } + + if ($realClassName === $fullyQualifiedName) { + return null; + } + + $parent = $node->getAttribute(AttributeKey::PARENT_NODE); + + // do not FQN use imports + if ($parent instanceof UseUse) { + return new Name($realClassName); + } + + return new FullyQualified($realClassName); + } + + private function resolveFullyQualifiedName(Name $name): string + { + $parent = $name->getAttribute(AttributeKey::PARENT_NODE); + // for some reason, Param gets already corrected name + if (! $parent instanceof Param) { + return $this->getName($name); + } + + /** @var Name|null $originalName */ + $originalName = $name->getAttribute(AttributeKey::ORIGINAL_NAME); + if ($originalName === null) { + return $this->getName($name); + } + + // replace parts from the old one + $originalReversedParts = array_reverse($originalName->parts); + $resolvedReversedParts = array_reverse($name->parts); + + $mergedReversedParts = $originalReversedParts + $resolvedReversedParts; + $mergedParts = array_reverse($mergedReversedParts); + + return implode('\\', $mergedParts); + } +} diff --git a/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/FixClassCaseSensitivityNameRectorTest.php b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/FixClassCaseSensitivityNameRectorTest.php new file mode 100644 index 00000000000..7fc260ac24b --- /dev/null +++ b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/FixClassCaseSensitivityNameRectorTest.php @@ -0,0 +1,34 @@ +doTestFileInfo($fileInfo); + } + + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + protected function getRectorClass(): string + { + return FixClassCaseSensitivityNameRector::class; + } +} diff --git a/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/fixture.php.inc b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..acad712f40e --- /dev/null +++ b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/fixture.php.inc @@ -0,0 +1,31 @@ + +----- + diff --git a/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/namespace_and_constants.php.inc b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/namespace_and_constants.php.inc new file mode 100644 index 00000000000..6cfc044552f --- /dev/null +++ b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/namespace_and_constants.php.inc @@ -0,0 +1,31 @@ + +----- + diff --git a/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/param_type.php.inc b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/param_type.php.inc new file mode 100644 index 00000000000..7c43bf34a22 --- /dev/null +++ b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/param_type.php.inc @@ -0,0 +1,31 @@ + +----- + diff --git a/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/skip_self_parent.php.inc b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/skip_self_parent.php.inc new file mode 100644 index 00000000000..fa83443dcc3 --- /dev/null +++ b/rules/code-quality/tests/Rector/Name/FixClassCaseSensitivityNameRector/Fixture/skip_self_parent.php.inc @@ -0,0 +1,11 @@ +