diff --git a/README.md b/README.md index 9e52a12..dfba5d9 100644 --- a/README.md +++ b/README.md @@ -261,3 +261,19 @@ an anonymous class declaration in a case when said class constructor doesn't con * `remove_for_anonymous_classes` - if its set to `true`, then braces for anonymous classes without constructor arguments will be removed. **Default**: `false`. + +### `Ely/remove_class_name_method_usages` (Yii2) + +Replaces Yii2 [`BaseObject::className()`](https://github.com/yiisoft/yii2/blob/e53fc0ded1/framework/base/BaseObject.php#L84) +usages with native `::class` keyword, introduced in PHP 5.5. + +```diff +--- Original ++++ New +@@ @@ + + */ +final class RemoveClassNameMethodUsagesFixer extends AbstractFixer { + + /** + * @inheritdoc + */ + public function getDefinition() { + return new FixerDefinition( + 'Converts Yii2 `BaseObject::className()` method usage into `::class` keyword.', + [ + new CodeSample( + 'isTokenKindFound(T_STRING); + } + + /** + * {@inheritdoc} + */ + public function isRisky() { + return true; + } + + /** + * {@inheritdoc} + */ + protected function applyFix(SplFileInfo $file, Tokens $tokens) { + for ($index = $tokens->count() - 4; $index > 0; --$index) { + $candidate = $this->getReplaceCandidate($tokens, $index); + if ($candidate === null) { + continue; + } + + $this->fixClassNameMethodUsage( + $tokens, + $index, + $candidate[0], // brace open + $candidate[1] // brace close + ); + } + } + + /** + * @param Tokens $tokens + * @param int $index + * + * @return null|array + */ + private function getReplaceCandidate(Tokens $tokens, $index) { + if (!$tokens[$index]->isGivenKind(T_STRING)) { + return null; + } + + $braceOpenIndex = $tokens->getNextMeaningfulToken($index); + if (!$tokens[$braceOpenIndex]->equals('(')) { + return null; + } + + $braceCloseIndex = $tokens->getNextMeaningfulToken($braceOpenIndex); + if (!$tokens[$braceCloseIndex]->equals(')')) { + return null; + } + + $doubleColon = $tokens->getPrevMeaningfulToken($index); + if (!$tokens[$doubleColon]->isGivenKind([T_DOUBLE_COLON])) { + return null; + } + + $methodName = $tokens[$index]->getContent(); + if ($methodName !== 'className') { + return null; + } + + return [ + $braceOpenIndex, + $braceCloseIndex, + ]; + } + + /** + * @param Tokens $tokens + * @param int $index + * @param int $braceOpenIndex + * @param int $braceCloseIndex + */ + private function fixClassNameMethodUsage(Tokens $tokens, int $index, int $braceOpenIndex, int $braceCloseIndex) { + $tokens->clearTokenAndMergeSurroundingWhitespace($braceCloseIndex); + $tokens->clearTokenAndMergeSurroundingWhitespace($braceOpenIndex); + $tokens->clearAt($index); + $tokens->insertAt($index, new Token([CT::T_CLASS_CONSTANT, 'class'])); + } + +} diff --git a/src/Rules.php b/src/Rules.php index f741443..0785f2d 100644 --- a/src/Rules.php +++ b/src/Rules.php @@ -65,6 +65,7 @@ class Rules { 'Ely/new_with_braces' => [ 'remove_for_anonymous_classes' => true, ], + 'Ely/remove_class_name_method_usages' => true, ]; public static function create(array $overwrittenRules = []): array { diff --git a/tests/Fixer/LanguageConstruct/RemoveClassNameMethodUsagesFixerTest.php b/tests/Fixer/LanguageConstruct/RemoveClassNameMethodUsagesFixerTest.php new file mode 100644 index 0000000..5059c2f --- /dev/null +++ b/tests/Fixer/LanguageConstruct/RemoveClassNameMethodUsagesFixerTest.php @@ -0,0 +1,67 @@ +doTest($expected, $input); + } + + public function provideFixCases() { + return [ + [ + '