From f51b3d3a71d6dfc1466d47ececd89744cf352273 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 23 May 2019 19:08:44 +0200 Subject: [PATCH] [PHP] Add StringClassNameToClassConstantRector --- config/level/coding-style/coding-style.yaml | 3 + config/level/php/php55.yaml | 2 + .../StringClassNameToClassConstantRector.php | 104 ++++++++++++++++++ .../Fixture/fixture.php.inc | 35 ++++++ .../Fixture/skip_error.php.inc | 13 +++ ...ringClassNameToClassConstantRectorTest.php | 19 ++++ src/Util/RectorStrings.php | 14 +++ 7 files changed, 190 insertions(+) create mode 100644 config/level/php/php55.yaml create mode 100644 packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php create mode 100644 packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/fixture.php.inc create mode 100644 packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/skip_error.php.inc create mode 100644 packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/StringClassNameToClassConstantRectorTest.php diff --git a/config/level/coding-style/coding-style.yaml b/config/level/coding-style/coding-style.yaml index 5c1b8ca97fd..b06484eb41a 100644 --- a/config/level/coding-style/coding-style.yaml +++ b/config/level/coding-style/coding-style.yaml @@ -14,3 +14,6 @@ services: Rector\CodingStyle\Rector\ClassConst\SplitGroupedConstantsAndPropertiesRector: ~ Rector\CodingStyle\Rector\String_\SplitStringClassConstantToClassConstFetchRector: ~ Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~ + + # 'ClassName' → ClassName::class + Rector\Php\Rector\String_\StringClassNameToClassConstantRector: ~ diff --git a/config/level/php/php55.yaml b/config/level/php/php55.yaml new file mode 100644 index 00000000000..7f5e79d1822 --- /dev/null +++ b/config/level/php/php55.yaml @@ -0,0 +1,2 @@ +services: + Rector\Php\Rector\String_\StringClassNameToClassConstantRector: ~ diff --git a/packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php b/packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php new file mode 100644 index 00000000000..f7d96fc677f --- /dev/null +++ b/packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php @@ -0,0 +1,104 @@ +classesToSkip = $classesToSkip; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Replace string class names by ::class constant', [ + new CodeSample( + <<<'CODE_SAMPLE' +class AnotherClass +{ +} + +class SomeClass +{ + public function run() + { + return 'AnotherClass'; + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class AnotherClass +{ +} + +class SomeClass +{ + public function run() + { + return \AnotherClass::class; + } +} +CODE_SAMPLE + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [String_::class]; + } + + /** + * @param String_ $node + */ + public function refactor(Node $node): ?Node + { + $classLikeName = $node->value; + if (! $this->classLikeExists($classLikeName)) { + return null; + } + + if (RectorStrings::isInArrayInsensitive($classLikeName, $this->classesToSkip)) { + return null; + } + + return new Node\Expr\ClassConstFetch(new Node\Name\FullyQualified($classLikeName), 'class'); + } + + private function classLikeExists(string $classLikeName): bool + { + if (class_exists($classLikeName)) { + return true; + } + + if (interface_exists($classLikeName)) { + return true; + } + + return trait_exists($classLikeName); + } +} diff --git a/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/fixture.php.inc b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..ca248b4f015 --- /dev/null +++ b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/fixture.php.inc @@ -0,0 +1,35 @@ + +----- + diff --git a/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/skip_error.php.inc b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/skip_error.php.inc new file mode 100644 index 00000000000..39ce1d9e7e5 --- /dev/null +++ b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/skip_error.php.inc @@ -0,0 +1,13 @@ +doTestFiles([__DIR__ . '/Fixture/fixture.php.inc', __DIR__ . '/Fixture/skip_error.php.inc']); + } + + protected function getRectorClass(): string + { + return StringClassNameToClassConstantRector::class; + } +} diff --git a/src/Util/RectorStrings.php b/src/Util/RectorStrings.php index 516011196a7..e24591c8167 100644 --- a/src/Util/RectorStrings.php +++ b/src/Util/RectorStrings.php @@ -18,6 +18,20 @@ final class RectorStrings return $privatesCaller->callPrivateMethod(new StringInput(''), 'tokenize', $command); } + /** + * @param string[] $array + */ + public static function isInArrayInsensitive(string $checkedItem, array $array): bool + { + foreach ($array as $item) { + if (Strings::lower($item) === Strings::lower($checkedItem)) { + return true; + } + } + + return false; + } + public static function camelCaseToDashes(string $input): string { return self::camelCaseToGlue($input, '-');