Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bunch of enum issues #6280

Merged
merged 1 commit into from Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions doc/list.rst
Expand Up @@ -166,17 +166,17 @@ List of Available Rules
Configuration options:

- | ``elements``
| Dictionary of `const|method|property|trait_import` => `none|one|only_if_meta` values.
| Dictionary of `const|method|property|trait_import|case` => `none|one|only_if_meta` values.
| Allowed types: ``array``
| Default value: ``['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none']``
| Default value: ``['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none', 'case' => 'none']``


Part of rule sets `@PhpCsFixer <./ruleSets/PhpCsFixer.rst>`_ `@Symfony <./ruleSets/Symfony.rst>`_

`Source PhpCsFixer\\Fixer\\ClassNotation\\ClassAttributesSeparationFixer <./../src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php>`_
- `class_definition <./rules/class_notation/class_definition.rst>`_

Whitespace around the keywords of a class, trait or interfaces definition should be one space.
Whitespace around the keywords of a class, trait, enum or interfaces definition should be one space.

Configuration options:

Expand Down Expand Up @@ -1578,7 +1578,7 @@ List of Available Rules
`Source PhpCsFixer\\Fixer\\ControlStructure\\NoUnneededCurlyBracesFixer <./../src/Fixer/ControlStructure/NoUnneededCurlyBracesFixer.php>`_
- `no_unneeded_final_method <./rules/class_notation/no_unneeded_final_method.rst>`_

A ``final`` class must not have ``final`` methods and ``private`` methods must not be ``final``.
Removes ``final`` from methods where possible.

*warning risky* Risky when child class overrides a ``private`` method.

Expand Down
4 changes: 2 additions & 2 deletions doc/rules/class_notation/class_attributes_separation.rst
Expand Up @@ -11,12 +11,12 @@ Configuration
``elements``
~~~~~~~~~~~~

Dictionary of ``const|method|property|trait_import`` =>
Dictionary of ``const|method|property|trait_import|case`` =>
``none|one|only_if_meta`` values.

Allowed types: ``array``

Default value: ``['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none']``
Default value: ``['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none', 'case' => 'none']``

Examples
--------
Expand Down
4 changes: 2 additions & 2 deletions doc/rules/class_notation/class_definition.rst
Expand Up @@ -2,8 +2,8 @@
Rule ``class_definition``
=========================

Whitespace around the keywords of a class, trait or interfaces definition should
be one space.
Whitespace around the keywords of a class, trait, enum or interfaces definition
should be one space.

Configuration
-------------
Expand Down
3 changes: 1 addition & 2 deletions doc/rules/class_notation/no_unneeded_final_method.rst
Expand Up @@ -2,8 +2,7 @@
Rule ``no_unneeded_final_method``
=================================

A ``final`` class must not have ``final`` methods and ``private`` methods must
not be ``final``.
Removes ``final`` from methods where possible.

Warning
-------
Expand Down
4 changes: 2 additions & 2 deletions doc/rules/index.rst
Expand Up @@ -144,7 +144,7 @@ Class Notation
Class, trait and interface elements must be separated with one or none blank line.
- `class_definition <./class_notation/class_definition.rst>`_

Whitespace around the keywords of a class, trait or interfaces definition should be one space.
Whitespace around the keywords of a class, trait, enum or interfaces definition should be one space.
- `final_class <./class_notation/final_class.rst>`_ *(risky)*

All classes must be final, except abstract ones and Doctrine entities.
Expand All @@ -165,7 +165,7 @@ Class Notation
Convert PHP4-style constructors to ``__construct``.
- `no_unneeded_final_method <./class_notation/no_unneeded_final_method.rst>`_ *(risky)*

A ``final`` class must not have ``final`` methods and ``private`` methods must not be ``final``.
Removes ``final`` from methods where possible.
- `ordered_class_elements <./class_notation/ordered_class_elements.rst>`_

Orders the elements of classes/interfaces/traits.
Expand Down
9 changes: 7 additions & 2 deletions src/AbstractDoctrineAnnotationFixer.php
Expand Up @@ -58,6 +58,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
$docCommentToken,
$this->configuration['ignored_tags']
);

$this->fixAnnotations($doctrineAnnotationTokens);
$tokens[$index] = new Token([T_DOC_COMMENT, $doctrineAnnotationTokens->getCode()]);
}
Expand Down Expand Up @@ -211,7 +212,7 @@ private function nextElementAcceptsDoctrineAnnotations(Tokens $tokens, int $inde
}
} while ($tokens[$index]->isGivenKind([T_ABSTRACT, T_FINAL]));

if ($tokens[$index]->isClassy()) {
if ($tokens[$index]->isGivenKind(T_CLASS)) {
return true;
}

Expand All @@ -225,6 +226,10 @@ private function nextElementAcceptsDoctrineAnnotations(Tokens $tokens, int $inde
$index = $tokens->getNextMeaningfulToken($index);
}

return isset($this->classyElements[$index]);
if (!isset($this->classyElements[$index])) {
return false;
}

return $tokens[$this->classyElements[$index]['classIndex']]->isGivenKind(T_CLASS); // interface, enums and traits cannot have doctrine annotations
}
}
2 changes: 1 addition & 1 deletion src/Fixer/Basic/BracesFixer.php
Expand Up @@ -297,7 +297,7 @@ private function fixDoWhile(Tokens $tokens): void

private function fixIndents(Tokens $tokens): void
{
$classyTokens = Token::getClassyTokenKinds();
$classyTokens = [T_CLASS, T_TRAIT, T_INTERFACE]; // FIXME use Token::getClassyTokenKinds() when ENUM tests are made
$classyAndFunctionTokens = array_merge([T_FUNCTION], $classyTokens);
$controlTokens = $this->getControlTokens();
$indentTokens = array_filter(
Expand Down
7 changes: 4 additions & 3 deletions src/Fixer/ClassNotation/ClassAttributesSeparationFixer.php
Expand Up @@ -204,11 +204,11 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('elements', 'Dictionary of `const|method|property|trait_import` => `none|one|only_if_meta` values.'))
(new FixerOptionBuilder('elements', 'Dictionary of `const|method|property|trait_import|case` => `none|one|only_if_meta` values.'))
->setAllowedTypes(['array'])
->setAllowedValues([static function (array $option): bool {
foreach ($option as $type => $spacing) {
$supportedTypes = ['const', 'method', 'property', 'trait_import'];
$supportedTypes = ['const', 'method', 'property', 'trait_import', 'case'];

if (!\in_array($type, $supportedTypes, true)) {
throw new InvalidOptionsException(
Expand Down Expand Up @@ -241,6 +241,7 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn
'method' => self::SPACING_ONE,
'property' => self::SPACING_ONE,
'trait_import' => self::SPACING_NONE,
'case' => self::SPACING_NONE,
])
->getOption(),
]);
Expand Down Expand Up @@ -542,7 +543,7 @@ private function getLastTokenIndexOfClassElement(Tokens $tokens, array $class, a
if (!$tokens[$elementEndIndex]->equals(';')) {
$elementEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $tokens->getNextTokenOfKind($element['index'], ['{']));
}
} else { // const or property
} else { // 'const', 'property', enum-'case', or 'method' of an interface
$elementEndIndex = $tokens->getNextTokenOfKind($element['index'], [';']);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Fixer/ClassNotation/ClassDefinitionFixer.php
Expand Up @@ -38,7 +38,7 @@ final class ClassDefinitionFixer extends AbstractFixer implements ConfigurableFi
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Whitespace around the keywords of a class, trait or interfaces definition should be one space.',
'Whitespace around the keywords of a class, trait, enum or interfaces definition should be one space.',
[
new CodeSample(
'<?php
Expand Down
Expand Up @@ -68,7 +68,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
$classLevel = 0;

for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
if ($tokens[$index]->isClassy()) {
if ($tokens[$index]->isGivenKind([T_CLASS, T_TRAIT])) { // Enums and interfaces do not have properties
++$classLevel;
$inClass[$classLevel] = 1;

Expand Down
43 changes: 33 additions & 10 deletions src/Fixer/ClassNotation/NoUnneededFinalMethodFixer.php
Expand Up @@ -36,7 +36,7 @@ final class NoUnneededFinalMethodFixer extends AbstractFixer implements Configur
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'A `final` class must not have `final` methods and `private` methods must not be `final`.',
'Removes `final` from methods where possible.',
[
new CodeSample(
'<?php
Expand Down Expand Up @@ -78,7 +78,15 @@ final private function bar1() {}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAllTokenKindsFound([T_CLASS, T_FINAL]);
if (!$tokens->isAllTokenKindsFound([T_FINAL, T_FUNCTION])) {
return false;
}

if (\defined('T_ENUM') && $tokens->isTokenKindFound(T_ENUM)) { // @TODO: drop condition when PHP 8.1+ is required
return true;
}

return $tokens->isTokenKindFound(T_CLASS);
}

public function isRisky(): bool
Expand All @@ -91,10 +99,10 @@ public function isRisky(): bool
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
foreach ($this->getClassMethods($tokens) as $element) {
foreach ($this->getMethods($tokens) as $element) {
$index = $element['method_final_index'];

if ($element['class_is_final']) {
if ($element['method_of_enum'] || $element['class_is_final']) {
$this->clearFinal($tokens, $index);

continue;
Expand All @@ -121,11 +129,12 @@ protected function createConfigurationDefinition(): FixerConfigurationResolverIn
]);
}

private function getClassMethods(Tokens $tokens): \Generator
private function getMethods(Tokens $tokens): \Generator
{
$tokensAnalyzer = new TokensAnalyzer($tokens);
$modifierKinds = [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_FINAL, T_ABSTRACT, T_STATIC];

$enums = [];
$classesAreFinal = [];
$elements = $tokensAnalyzer->getClassyElements();

Expand All @@ -144,13 +153,10 @@ private function getClassMethods(Tokens $tokens): \Generator

$classIndex = $element['classIndex'];

if (!\array_key_exists($classIndex, $classesAreFinal)) {
$prevToken = $tokens[$tokens->getPrevMeaningfulToken($classIndex)];
$classesAreFinal[$classIndex] = $prevToken->isGivenKind(T_FINAL);
if (!\array_key_exists($classIndex, $enums)) {
$enums[$classIndex] = \defined('T_ENUM') && $tokens[$classIndex]->isGivenKind(T_ENUM); // @TODO: drop condition when PHP 8.1+ is required
}

$element['class_is_final'] = $classesAreFinal[$classIndex];
$element['method_is_constructor'] = '__construct' === strtolower($tokens[$tokens->getNextMeaningfulToken($index)]->getContent());
$element['method_final_index'] = null;
$element['method_is_private'] = false;

Expand All @@ -166,6 +172,23 @@ private function getClassMethods(Tokens $tokens): \Generator
}
} while ($tokens[$previous]->isGivenKind($modifierKinds));

if ($enums[$classIndex]) {
$element['method_of_enum'] = true;

yield $element;

continue;
}

if (!\array_key_exists($classIndex, $classesAreFinal)) {
$prevToken = $tokens[$tokens->getPrevMeaningfulToken($classIndex)];
$classesAreFinal[$classIndex] = $prevToken->isGivenKind(T_FINAL);
}

$element['method_of_enum'] = false;
$element['class_is_final'] = $classesAreFinal[$classIndex];
$element['method_is_constructor'] = '__construct' === strtolower($tokens[$tokens->getNextMeaningfulToken($index)]->getContent());

yield $element;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Fixer/ClassNotation/OrderedClassElementsFixer.php
Expand Up @@ -150,7 +150,7 @@ public function configure(array $configuration): void
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
return $tokens->isAnyTokenKindsFound([T_CLASS, T_TRAIT, T_INTERFACE]); // FIXME use Token::getClassyTokenKinds(false)
}

/**
Expand Down Expand Up @@ -237,7 +237,7 @@ public function getPriority(): int
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($i = 1, $count = $tokens->count(); $i < $count; ++$i) {
if (!$tokens[$i]->isClassy()) {
if (!$tokens[$i]->isGivenKind([T_CLASS, T_TRAIT, T_INTERFACE])) { // FIXME use "isClassy"
continue;
}

Expand Down
15 changes: 14 additions & 1 deletion src/Fixer/ClassNotation/ProtectedToPrivateFixer.php
Expand Up @@ -68,6 +68,10 @@ public function getPriority(): int
*/
public function isCandidate(Tokens $tokens): bool
{
if (\defined('T_ENUM') && $tokens->isAllTokenKindsFound([T_ENUM, T_PROTECTED])) { // @TODO: drop condition when PHP 8.1+ is required
return true;
}

return $tokens->isAllTokenKindsFound([T_CLASS, T_FINAL, T_PROTECTED]);
}

Expand All @@ -84,6 +88,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
}

$classesCandidate = [];
$classElementTypes = ['method' => true, 'property' => true, 'const' => true];

foreach ($tokensAnalyzer->getClassyElements() as $index => $element) {
$classIndex = $element['classIndex'];
Expand All @@ -93,7 +98,11 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
}

if (false === $classesCandidate[$classIndex]) {
continue; // not "final" class, "extends", is "anonymous" or uses trait
continue; // not "final" class, "extends", is "anonymous", enum or uses trait
}

if (!isset($classElementTypes[$element['type']])) {
continue;
}

$previous = $index;
Expand Down Expand Up @@ -125,6 +134,10 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void

private function isClassCandidate(Tokens $tokens, int $classIndex): bool
{
if (\defined('T_ENUM') && $tokens[$classIndex]->isGivenKind(T_ENUM)) { // @TODO: drop condition when PHP 8.1+ is required
return true;
}

$prevToken = $tokens[$tokens->getPrevMeaningfulToken($classIndex)];

if (!$prevToken->isGivenKind(T_FINAL)) {
Expand Down
Expand Up @@ -130,7 +130,7 @@ protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $en
$tokenAnalyzer = new TokensAnalyzer($tokens);

for ($index = $startIndex; $index < $endIndex; ++$index) {
if (!$tokens[$index]->isClassy() || !$tokenAnalyzer->isAnonymousClass($index)) {
if (!$tokens[$index]->isGivenKind(T_CLASS) || !$tokenAnalyzer->isAnonymousClass($index)) {
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Fixer/Phpdoc/PhpdocReturnSelfReferenceFixer.php
Expand Up @@ -102,7 +102,7 @@ public function test2()
*/
public function isCandidate(Tokens $tokens): bool
{
return \count($tokens) > 10 && $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound([T_CLASS, T_INTERFACE]);
return \count($tokens) > 10 && $tokens->isAllTokenKindsFound([T_DOC_COMMENT, T_FUNCTION]) && $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Fixer/Phpdoc/PhpdocVarWithoutNameFixer.php
Expand Up @@ -70,7 +70,7 @@ public function getPriority(): int
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
return $tokens->isTokenKindFound(T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound([T_CLASS, T_TRAIT]);
}

/**
Expand Down
12 changes: 10 additions & 2 deletions src/Tokenizer/Token.php
Expand Up @@ -102,7 +102,15 @@ public static function getCastTokenKinds(): array
*/
public static function getClassyTokenKinds(): array
{
static $classTokens = [T_CLASS, T_TRAIT, T_INTERFACE];
static $classTokens;

if (null === $classTokens) {
$classTokens = [T_CLASS, T_TRAIT, T_INTERFACE];

if (\defined('T_ENUM')) { // @TODO: drop condition when PHP 8.1+ is required
$classTokens[] = T_ENUM;
}
}

return $classTokens;
}
Expand Down Expand Up @@ -366,7 +374,7 @@ public function isCast(): bool
}

/**
* Check if token is one of classy tokens: T_CLASS, T_INTERFACE or T_TRAIT.
* Check if token is one of classy tokens: T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM.
*/
public function isClassy(): bool
{
Expand Down