diff --git a/SymfonyCustom/Sniffs/Arrays/ArrayDeclarationSniff.php b/SymfonyCustom/Sniffs/Arrays/ArrayDeclarationSniff.php index f2d1489..c088e35 100644 --- a/SymfonyCustom/Sniffs/Arrays/ArrayDeclarationSniff.php +++ b/SymfonyCustom/Sniffs/Arrays/ArrayDeclarationSniff.php @@ -651,11 +651,7 @@ public function processMultiLineArray(File $phpcsFile, int $stackPtr, int $start ); if ($fix) { - if (0 === $found) { - $phpcsFile->fixer->addContent($index['index'] - 1, str_repeat(' ', $expected)); - } else { - $phpcsFile->fixer->replaceToken($index['index'] - 1, str_repeat(' ', $expected)); - } + $this->align($phpcsFile, $index['index'], $expected, $found); } continue; @@ -679,20 +675,7 @@ public function processMultiLineArray(File $phpcsFile, int $stackPtr, int $start ); if ($fix) { - if ('newline' === $found) { - $prev = $phpcsFile->findPrevious(T_WHITESPACE, $index['value'] - 1, null, true); - $phpcsFile->fixer->beginChangeset(); - for ($i = $prev + 1; $i < $index['value']; $i++) { - $phpcsFile->fixer->replaceToken($i, ''); - } - - $phpcsFile->fixer->replaceToken($index['value'] - 1, str_repeat(' ', $expected)); - $phpcsFile->fixer->endChangeset(); - } elseif (0 === $found) { - $phpcsFile->fixer->addContent($index['arrow'] - 1, str_repeat(' ', $expected)); - } else { - $phpcsFile->fixer->replaceToken($index['arrow'] - 1, str_repeat(' ', $expected)); - } + $this->align($phpcsFile, $index['arrow'], $expected, $found); } continue; @@ -709,28 +692,40 @@ public function processMultiLineArray(File $phpcsFile, int $stackPtr, int $start $fix = $phpcsFile->addFixableError( 'Array value not aligned correctly; expected %s space(s) but found %s', - $index['arrow'], + $index['value'], 'ValueNotAligned', [$expected, $found] ); if ($fix) { - if ('newline' === $found) { - $prev = $phpcsFile->findPrevious(T_WHITESPACE, $index['value'] - 1, null, true); - $phpcsFile->fixer->beginChangeset(); - for ($i = $prev + 1; $i < $index['value']; $i++) { - $phpcsFile->fixer->replaceToken($i, ''); - } - - $phpcsFile->fixer->replaceToken($index['value'] - 1, str_repeat(' ', $expected)); - $phpcsFile->fixer->endChangeset(); - } elseif (0 === $found) { - $phpcsFile->fixer->addContent($index['value'] - 1, str_repeat(' ', $expected)); - } else { - $phpcsFile->fixer->replaceToken($index['value'] - 1, str_repeat(' ', $expected)); - } + $this->align($phpcsFile, $index['value'], $expected, $found); } } } } + + /** + * @param File $phpcsFile + * @param int $elementIndex + * @param int $expected + * @param int|string $found + */ + private function align(File $phpcsFile, int $elementIndex, int $expected, $found): void + { + if ('newline' === $found) { + $phpcsFile->fixer->beginChangeset(); + + $prev = $phpcsFile->findPrevious(T_WHITESPACE, $elementIndex - 1, null, true); + for ($i = $prev + 1; $i < $elementIndex; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->replaceToken($elementIndex - 1, str_repeat(' ', $expected)); + $phpcsFile->fixer->endChangeset(); + } elseif (0 === $found) { + $phpcsFile->fixer->addContent($elementIndex - 1, str_repeat(' ', $expected)); + } else { + $phpcsFile->fixer->replaceToken($elementIndex - 1, str_repeat(' ', $expected)); + } + } } diff --git a/SymfonyCustom/Sniffs/Commenting/ClassCommentSniff.php b/SymfonyCustom/Sniffs/Commenting/ClassCommentSniff.php index 380f19b..716ecdb 100644 --- a/SymfonyCustom/Sniffs/Commenting/ClassCommentSniff.php +++ b/SymfonyCustom/Sniffs/Commenting/ClassCommentSniff.php @@ -26,57 +26,46 @@ class ClassCommentSniff extends PEARClassCommentSniff 'category' => [ 'required' => false, 'allow_multiple' => false, - 'order_text' => 'precedes @package', ], 'package' => [ 'required' => false, 'allow_multiple' => false, - 'order_text' => 'follows @category', ], 'subpackage' => [ 'required' => false, 'allow_multiple' => false, - 'order_text' => 'follows @package', ], 'author' => [ 'required' => false, 'allow_multiple' => true, - 'order_text' => 'follows @subpackage (if used) or @package', ], 'copyright' => [ 'required' => false, 'allow_multiple' => true, - 'order_text' => 'follows @author', ], 'license' => [ 'required' => false, 'allow_multiple' => false, - 'order_text' => 'follows @copyright (if used) or @author', ], 'version' => [ 'required' => false, 'allow_multiple' => false, - 'order_text' => 'follows @license', ], 'link' => [ 'required' => false, 'allow_multiple' => true, - 'order_text' => 'follows @version', ], 'see' => [ 'required' => false, 'allow_multiple' => true, - 'order_text' => 'follows @link', ], 'since' => [ 'required' => false, 'allow_multiple' => false, - 'order_text' => 'follows @see (if used) or @link', ], 'deprecated' => [ 'required' => false, 'allow_multiple' => false, - 'order_text' => 'follows @since (if used) or @see (if used) or @link', ], ]; } diff --git a/SymfonyCustom/Sniffs/Commenting/DocCommentGroupSameTypeSniff.php b/SymfonyCustom/Sniffs/Commenting/DocCommentGroupSameTypeSniff.php index bf02197..f45996a 100644 --- a/SymfonyCustom/Sniffs/Commenting/DocCommentGroupSameTypeSniff.php +++ b/SymfonyCustom/Sniffs/Commenting/DocCommentGroupSameTypeSniff.php @@ -29,114 +29,94 @@ public function process(File $phpcsFile, $stackPtr): void { $tokens = $phpcsFile->getTokens(); - $previousType = ''; + $typeSeen = []; + $previousTag = false; + $previousIsCustom = false; + foreach ($tokens[$stackPtr]['comment_tags'] as $commentTag) { $currentType = $tokens[$commentTag]['content']; - $commentTagLine = $tokens[$commentTag]['line']; - - $previousString = $phpcsFile->findPrevious( - T_DOC_COMMENT_STRING, - $commentTag, - $stackPtr - ); + $currentIsCustom = !in_array($currentType, SniffHelper::TAGS); + $isNewType = !in_array($currentType, $typeSeen); - $previousTag = $phpcsFile->findPrevious( - T_DOC_COMMENT_TAG, - $commentTag - 1, - $stackPtr - ); + $commentTagLine = $tokens[$commentTag]['line']; + $previousString = $phpcsFile->findPrevious(T_DOC_COMMENT_STRING, $commentTag, $stackPtr); $previousLine = -1; + if (false !== $previousString) { $previousLine = $tokens[$previousString]['line']; $previousElement = $previousString; } if (false !== $previousTag) { + $previousType = $tokens[$previousTag]['content']; $previousTagLine = $tokens[$previousTag]['line']; if ($previousTagLine > $previousLine) { $previousLine = $previousTagLine; $previousElement = $previousTag; } + } else { + $previousType = null; } if (isset($previousElement) && $previousLine >= 0) { - $currentIsCustom = !in_array($currentType, SniffHelper::TAGS); - $previousIsCustom = '' !== $previousType - && !in_array($previousType, SniffHelper::TAGS); - - if (($previousType === $currentType) || ($currentIsCustom && $previousIsCustom)) { + if ($previousType === $currentType) { if ($previousLine !== $commentTagLine - 1) { - if ($previousType === $currentType) { - $fix = $phpcsFile->addFixableError( - 'Expected no empty lines between annotations of the same type', - $commentTag, - 'SameType' - ); - } else { - $fix = $phpcsFile->addFixableError( - 'Expected no empty lines between custom annotations', - $commentTag, - 'CustomType' - ); - } + $fix = $phpcsFile->addFixableError( + 'Expected no empty lines between annotations of the same type', + $commentTag, + 'SameType' + ); if ($fix) { - $phpcsFile->fixer->beginChangeset(); - $this->removeLines( - $phpcsFile, - $previousElement, - $previousLine + 1, - $commentTagLine - 1 - ); - $phpcsFile->fixer->endChangeset(); + $this->removeLines($phpcsFile, $previousElement, $previousLine + 1, $commentTagLine - 1); } } - } else { - if ($previousLine !== $commentTagLine - 2) { + } elseif ($currentIsCustom && $previousIsCustom) { + if ($previousLine !== $commentTagLine - 1) { $fix = $phpcsFile->addFixableError( - 'Expected exactly one empty line between annotations of different types', + 'Expected no empty lines between custom annotations', $commentTag, - 'DifferentType' + 'CustomType' ); if ($fix) { - $phpcsFile->fixer->beginChangeset(); - - if ($previousLine === $commentTagLine - 1) { - $firstOnLine = $phpcsFile->findFirstOnLine( - [], - $commentTag, - true - ); - $star = $phpcsFile->findNext( - T_DOC_COMMENT_STAR, - $firstOnLine - ); - $content = $phpcsFile->getTokensAsString( - $firstOnLine, - $star - $firstOnLine + 1 - ); - $phpcsFile->fixer->addContentBefore( - $firstOnLine, - $content.$phpcsFile->eolChar - ); - } else { - $this->removeLines( - $phpcsFile, - $previousElement, - $previousLine + 2, - $commentTagLine - 1 - ); - } - $phpcsFile->fixer->endChangeset(); + $this->removeLines($phpcsFile, $previousElement, $previousLine + 1, $commentTagLine - 1); + } + } + } elseif (!$currentIsCustom && !$isNewType) { + $phpcsFile->addError( + 'Annotation of the same type should be together', + $commentTag, + 'GroupSameType' + ); + } elseif ($previousLine !== $commentTagLine - 2) { + $fix = $phpcsFile->addFixableError( + 'Expected exactly one empty line between annotations of different types', + $commentTag, + 'DifferentType' + ); + + if ($fix) { + if ($previousLine === $commentTagLine - 1) { + $firstOnLine = $phpcsFile->findFirstOnLine([], $commentTag, true); + $star = $phpcsFile->findNext(T_DOC_COMMENT_STAR, $firstOnLine); + $content = $phpcsFile->getTokensAsString($firstOnLine, $star - $firstOnLine + 1); + + $phpcsFile->fixer->addContentBefore($firstOnLine, $content.$phpcsFile->eolChar); + } else { + $this->removeLines($phpcsFile, $previousElement, $previousLine + 2, $commentTagLine - 1); } } } } - $previousType = $currentType; + $previousTag = $commentTag; + $previousIsCustom = $currentIsCustom; + if (!$currentIsCustom && $isNewType) { + $typeSeen[] = $currentType; + } } } @@ -150,6 +130,8 @@ private function removeLines(File $phpcsFile, int $fromPtr, int $fromLine, int $ { $tokens = $phpcsFile->getTokens(); + $phpcsFile->fixer->beginChangeset(); + for ($i = $fromPtr;; $i++) { if ($tokens[$i]['line'] > $toLine) { break; @@ -159,5 +141,7 @@ private function removeLines(File $phpcsFile, int $fromPtr, int $fromLine, int $ $phpcsFile->fixer->replaceToken($i, ''); } } + + $phpcsFile->fixer->endChangeset(); } } diff --git a/SymfonyCustom/Sniffs/Errors/UserDeprecatedSniff.php b/SymfonyCustom/Sniffs/Errors/UserDeprecatedSniff.php index fa0c62e..f67babc 100644 --- a/SymfonyCustom/Sniffs/Errors/UserDeprecatedSniff.php +++ b/SymfonyCustom/Sniffs/Errors/UserDeprecatedSniff.php @@ -38,22 +38,32 @@ public function process(File $phpcsFile, $stackPtr): void do { $string = $phpcsFile->findNext(T_STRING, $opener, $closer); - if (false === $string) { break; } - if ('E_USER_DEPRECATED' === $tokens[$string]['content'] && '@' !== $tokens[$stackPtr - 1]['content']) { - $phpcsFile->addError( - 'Calls to trigger_error with type E_USER_DEPRECATED must be switched to opt-in via @ operator', - $stackPtr, - 'Invalid' - ); + $opener = $string + 1; - break; - } else { - $opener = $string + 1; + if ('E_USER_DEPRECATED' !== $tokens[$string]['content']) { + continue; + } + + if ('@' === $tokens[$stackPtr - 1]['content']) { + continue; } + + if ('@' === $tokens[$stackPtr - 2]['content'] + && 'T_NS_SEPARATOR' === $tokens[$stackPtr - 1]['type'] + ) { + continue; + } + + $phpcsFile->addError( + 'Calls to trigger_error with type E_USER_DEPRECATED must be switched to opt-in via @ operator', + $stackPtr, + 'Invalid' + ); + break; } while ($opener < $closer); } } diff --git a/SymfonyCustom/Sniffs/WhiteSpace/UnaryOperatorSpacingSniff.php b/SymfonyCustom/Sniffs/WhiteSpace/UnaryOperatorSpacingSniff.php index 35384d5..8b4ded6 100644 --- a/SymfonyCustom/Sniffs/WhiteSpace/UnaryOperatorSpacingSniff.php +++ b/SymfonyCustom/Sniffs/WhiteSpace/UnaryOperatorSpacingSniff.php @@ -17,7 +17,7 @@ class UnaryOperatorSpacingSniff implements Sniff */ public function register(): array { - return [T_MINUS, T_PLUS, T_BOOLEAN_NOT]; + return [T_MINUS, T_PLUS]; } /** @@ -28,21 +28,6 @@ public function process(File $phpcsFile, $stackPtr): void { $tokens = $phpcsFile->getTokens(); - // Check "!" operator. - if (T_BOOLEAN_NOT === $tokens[$stackPtr]['code'] && T_WHITESPACE === $tokens[$stackPtr + 1]['code']) { - $fix = $phpcsFile->addFixableError( - 'A unary operator statement must not be followed by a space', - $stackPtr, - 'BooleanNot' - ); - - if ($fix) { - $phpcsFile->fixer->replaceToken($stackPtr + 1, ''); - } - - return; - } - // Find the last syntax item to determine if this is an unary operator. $lastSyntaxItem = $phpcsFile->findPrevious( T_WHITESPACE, @@ -66,17 +51,15 @@ public function process(File $phpcsFile, $stackPtr): void ); // Check plus / minus value assignments or comparisons. - if (T_MINUS === $tokens[$stackPtr]['code'] || T_PLUS === $tokens[$stackPtr]['code']) { - if (!$operatorSuffixAllowed && T_WHITESPACE === $tokens[$stackPtr + 1]['code']) { - $fix = $phpcsFile->addFixableError( - 'A unary operator statement must not be followed by a space', - $stackPtr, - 'Invalid' - ); + if (!$operatorSuffixAllowed && T_WHITESPACE === $tokens[$stackPtr + 1]['code']) { + $fix = $phpcsFile->addFixableError( + 'A unary operator statement must not be followed by a space', + $stackPtr, + 'Invalid' + ); - if ($fix) { - $phpcsFile->fixer->replaceToken($stackPtr + 1, ''); - } + if ($fix) { + $phpcsFile->fixer->replaceToken($stackPtr + 1, ''); } } } diff --git a/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc b/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc index af4dc86..d7b8338 100644 --- a/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc +++ b/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc @@ -135,3 +135,15 @@ return [ DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], ]; + +[ + 0 => 1, + 1 + => 2, +]; + +[ + 0 => 1, + 1 => + 2, +]; diff --git a/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc.fixed b/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc.fixed index d4f8596..3211704 100644 --- a/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc.fixed +++ b/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.inc.fixed @@ -135,3 +135,13 @@ return [ DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], ]; + +[ + 0 => 1, + 1 => 2, +]; + +[ + 0 => 1, + 1 => 2, +]; diff --git a/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.php b/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.php index b7757c0..a838008 100644 --- a/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.php +++ b/SymfonyCustom/Tests/Arrays/ArrayDeclarationUnitTest.php @@ -51,6 +51,8 @@ protected function getErrorList(): array 100 => 3, 102 => 4, 107 => 2, + 142 => 1, + 148 => 1, ]; } diff --git a/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc b/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc index ca0f066..8634bcc 100644 --- a/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc +++ b/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc @@ -66,3 +66,11 @@ * @Route("/{id}/") * @param */ + +/** + * @param string $a + * + * @return string + * + * @param string $b + */ diff --git a/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc.fixed b/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc.fixed index e8a42ba..c8a2ae3 100644 --- a/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc.fixed +++ b/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.inc.fixed @@ -69,3 +69,11 @@ * * @param */ + +/** + * @param string $a + * + * @return string + * + * @param string $b + */ diff --git a/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.php b/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.php index c4c9d14..a39b6bd 100644 --- a/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.php +++ b/SymfonyCustom/Tests/Commenting/DocCommentGroupSameTypeUnitTest.php @@ -30,6 +30,7 @@ protected function getErrorList(): array 29 => 1, 33 => 1, 67 => 1, + 75 => 1, ]; } diff --git a/SymfonyCustom/Tests/Errors/UserDeprecatedUnitTest.inc b/SymfonyCustom/Tests/Errors/UserDeprecatedUnitTest.inc index 7f50b7b..865ea09 100644 --- a/SymfonyCustom/Tests/Errors/UserDeprecatedUnitTest.inc +++ b/SymfonyCustom/Tests/Errors/UserDeprecatedUnitTest.inc @@ -1,40 +1,9 @@ 1, + 3 => 1, + 6 => 1, ]; } diff --git a/SymfonyCustom/Tests/WhiteSpace/UnaryOperatorSpacingUnitTest.inc b/SymfonyCustom/Tests/WhiteSpace/UnaryOperatorSpacingUnitTest.inc index ffe2aa1..7909d3d 100644 --- a/SymfonyCustom/Tests/WhiteSpace/UnaryOperatorSpacingUnitTest.inc +++ b/SymfonyCustom/Tests/WhiteSpace/UnaryOperatorSpacingUnitTest.inc @@ -1,8 +1,5 @@ 1, - 7 => 1, + 6 => 1, 9 => 1, - 12 => 1, - 13 => 1, + 10 => 1, ]; } diff --git a/SymfonyCustom/ruleset.xml b/SymfonyCustom/ruleset.xml index f4072b2..e58071a 100755 --- a/SymfonyCustom/ruleset.xml +++ b/SymfonyCustom/ruleset.xml @@ -40,6 +40,11 @@ + + + + +