From a716712befa65055cc54b84d508e894c8839f23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bundyra?= Date: Thu, 7 Nov 2019 12:26:39 +0000 Subject: [PATCH 1/2] Feature: Array\Format - disallow comments and blank lines before arrows Using comment before arrow in array is disallowed. Additional empty lines before arrow in array are disallowed. Fixes also issue when empty line was not removed before the value. --- .../Sniffs/Arrays/FormatSniff.php | 109 ++++++++++-------- test/Sniffs/Arrays/FormatUnitTest.inc | 46 ++++++++ test/Sniffs/Arrays/FormatUnitTest.inc.fixed | 42 ++++++- test/Sniffs/Arrays/FormatUnitTest.php | 8 ++ 4 files changed, 155 insertions(+), 50 deletions(-) diff --git a/src/WebimpressCodingStandard/Sniffs/Arrays/FormatSniff.php b/src/WebimpressCodingStandard/Sniffs/Arrays/FormatSniff.php index a1aae00f..fd349e77 100644 --- a/src/WebimpressCodingStandard/Sniffs/Arrays/FormatSniff.php +++ b/src/WebimpressCodingStandard/Sniffs/Arrays/FormatSniff.php @@ -6,16 +6,14 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractArraySniff; +use PHP_CodeSniffer\Util\Tokens; +use function ltrim; use function str_repeat; use function strlen; -use function strpos; +use function trim; -use const T_CLOSE_CURLY_BRACKET; use const T_CLOSE_SHORT_ARRAY; -use const T_COMMENT; -use const T_DOC_COMMENT_OPEN_TAG; -use const T_DOUBLE_ARROW; use const T_WHITESPACE; /** @@ -39,6 +37,8 @@ * ]; * ``` * - array closing bracket in new line (code: `ClosingBracketInNewLine`). + * - no comment before arrow (code `CommentBeforeArrow`) + * - no blank line before arrow (code: `BlankLineBeforeArrow`) */ class FormatSniff extends AbstractArraySniff { @@ -124,57 +124,68 @@ protected function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $ar } } - $previousLine = $tokens[$arrayStart]['line']; - $next = $arrayStart; - while ($next = $phpcsFile->findNext(T_WHITESPACE, $next + 1, $arrayEnd, true)) { - if ($previousLine === $tokens[$next]['line']) { - if ($tokens[$next]['code'] !== T_COMMENT) { - $error = 'There must be one array element per line'; - $fix = $phpcsFile->addFixableError($error, $next, 'OneElementPerLine'); - - if ($fix) { - $phpcsFile->fixer->beginChangeset(); - if ($tokens[$next - 1]['code'] === T_WHITESPACE) { - $phpcsFile->fixer->replaceToken($next - 1, ''); - } - $phpcsFile->fixer->addNewlineBefore($next); - $phpcsFile->fixer->endChangeset(); - } - } - } else { - if ($previousLine < $tokens[$next]['line'] - 1 - && (! empty($tokens[$stackPtr]['conditions']) - || $previousLine === $tokens[$arrayStart]['line']) - ) { - $firstOnLine = $phpcsFile->findFirstOnLine([], $next, true); - - $error = 'Blank line is not allowed here'; - $fix = $phpcsFile->addFixableError($error, $firstOnLine - 1, 'BlankLine'); - - if ($fix) { - $phpcsFile->fixer->replaceToken($firstOnLine - 1, ''); + // $previousLine = $tokens[$arrayStart]['line']; + foreach ($indices as $element) { + $start = $element['index_start'] ?? $element['value_start']; + + // For some reasons empty array has value_start = false + if (! $start) { + continue; + } + + $nonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, $start - 1, null, true); + if ($tokens[$start]['line'] === $tokens[$nonEmpty]['line']) { + $error = 'There must be one array element per line'; + $fix = $phpcsFile->addFixableError($error, $start, 'OneElementPerLine'); + + if ($fix) { + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addNewline($nonEmpty); + if ($tokens[$nonEmpty + 1]['code'] === T_WHITESPACE) { + $phpcsFile->fixer->replaceToken($nonEmpty + 1, ''); } + $phpcsFile->fixer->endChangeset(); } } - if ($tokens[$next]['code'] === T_COMMENT - && (strpos($tokens[$next]['content'], '//') === 0 - || strpos($tokens[$next]['content'], '#') === 0) - ) { - $end = $next; - } elseif ($tokens[$next]['code'] === T_DOC_COMMENT_OPEN_TAG) { - $end = $tokens[$next]['comment_closer']; - } else { - $end = $phpcsFile->findEndOfStatement($next); - if ($tokens[$end]['code'] === T_DOUBLE_ARROW - || $tokens[$end]['code'] === T_CLOSE_CURLY_BRACKET - ) { - $end = $phpcsFile->findEndOfStatement($end); + $prev = $phpcsFile->findPrevious(T_WHITESPACE, $start - 1, null, true); + if ($tokens[$prev]['line'] < $tokens[$start]['line'] - 1) { + $blankLine = $tokens[$prev]['line'] === $tokens[$prev + 1]['line'] ? $prev + 2 : $prev + 1; + $error = 'Blank line is not allowed here'; + + $fix = $phpcsFile->addFixableError($error, $blankLine, 'BlankLine'); + if ($fix) { + $phpcsFile->fixer->replaceToken($blankLine, ''); } } - $previousLine = $tokens[$end]['line']; - $next = $end; + if (! isset($element['arrow'])) { + continue; + } + + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $element['arrow'] - 1, null, true); + $content = $phpcsFile->getTokensAsString($prev + 1, $element['arrow'] - $prev - 1); + if (trim($content) !== '') { + $error = 'Comment is not allowed before arrow in array'; + $comment = $phpcsFile->findNext(Tokens::$commentTokens, $prev + 1); + + $fix = $phpcsFile->addFixableError($error, $comment, 'CommentBeforeArrow'); + if ($fix) { + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addContentBefore($element['index_start'], ltrim($content)); + for ($i = $comment; $i < $element['arrow']; ++$i) { + $phpcsFile->fixer->replaceToken($i, ''); + } + $phpcsFile->fixer->endChangeset(); + } + } elseif ($tokens[$prev]['line'] < $tokens[$element['arrow']]['line'] - 1) { + $error = 'Blank line is not allowed before arrow in array'; + + $fix = $phpcsFile->addFixableError($error, $prev + 2, 'BlankLineBeforeArrow'); + if ($fix) { + $phpcsFile->fixer->replaceToken($prev + 2, ''); + } + } } if ($first = $phpcsFile->findFirstOnLine([], $arrayEnd, true)) { diff --git a/test/Sniffs/Arrays/FormatUnitTest.inc b/test/Sniffs/Arrays/FormatUnitTest.inc index 8b947e4c..0274d38e 100644 --- a/test/Sniffs/Arrays/FormatUnitTest.inc +++ b/test/Sniffs/Arrays/FormatUnitTest.inc @@ -87,3 +87,49 @@ $a = [ */ // 'key' => 'val', ]; + +$a = [ + 'a', + + // b + + 'c', +]; + +$a = [ + 'a', + + /* + multiline comment + */ + + 'b', +]; + +$x = [ + // comment + 'a', 'b', + 'd', + + + // comment 1 + 'i' => 'd', + //comment 2 + 'j' + + //comment 3 + + =>'r', + + 'r' + . 'x ', + // comment 4 + 'x1' + + => 'y1', +]; + +$a = [ + // COMMENT +]; +$a = [ /**/ ]; diff --git a/test/Sniffs/Arrays/FormatUnitTest.inc.fixed b/test/Sniffs/Arrays/FormatUnitTest.inc.fixed index 10c7727d..3f40d7cf 100644 --- a/test/Sniffs/Arrays/FormatUnitTest.inc.fixed +++ b/test/Sniffs/Arrays/FormatUnitTest.inc.fixed @@ -3,7 +3,6 @@ $a1 = ['foo', 'bar']; $a2 = [ 'foo', 'bar', - function() { }, @@ -100,3 +99,44 @@ $a = [ */ // 'key' => 'val', ]; + +$a = [ + 'a', + + // b + 'c', +]; + +$a = [ + 'a', + + /* + multiline comment + */ + 'b', +]; + +$x = [ + // comment + 'a', +'b', + 'd', + + + // comment 1 + 'i' => 'd', + //comment 2 + //comment 3 + 'j' + =>'r', + 'r' + . 'x ', + // comment 4 + 'x1' + => 'y1', +]; + +$a = [ + // COMMENT +]; +$a = [/**/]; diff --git a/test/Sniffs/Arrays/FormatUnitTest.php b/test/Sniffs/Arrays/FormatUnitTest.php index 7effcd76..564cc626 100644 --- a/test/Sniffs/Arrays/FormatUnitTest.php +++ b/test/Sniffs/Arrays/FormatUnitTest.php @@ -12,6 +12,7 @@ protected function getErrorList(string $testFile = '') : array { return [ 2 => 2, + 6 => 1, 14 => 2, 16 => 2, 19 => 1, @@ -34,6 +35,13 @@ protected function getErrorList(string $testFile = '') : array 74 => 1, 75 => 1, 76 => 1, + 95 => 1, + 105 => 1, + 111 => 1, + 120 => 1, + 123 => 1, + 128 => 1, + 135 => 2, ]; } From 7f7d1471ff388355a7d0a75e2b16e0c52c268451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bundyra?= Date: Sun, 10 Nov 2019 23:49:38 +0000 Subject: [PATCH 2/2] Adds CHANGELOG entries for #51 --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08280c5a..a2ead2c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,9 @@ All notable changes to this project will be documented in this file, in reverse - [#50](https://github.com/webimpress/coding-standard/pull/50) adds check for open and close of doc block comment in `Commenting\DocComment`. Only short version is allowed: `/**` and `*/`. Additional asterisk are disallowed. +- [#51](https://github.com/webimpress/coding-standard/pull/51) adds check for blank lines and comments before arrow in arrays in `Array\Format` sniff. + Arrow must be after the index value, can be in new line, but any additional lines or comments are disallowed. + ### Changed - [#42](https://github.com/webimpress/coding-standard/pull/42) changes `NamingConventions\ValidVariableName` to require variable names be in strict camelCase. It means two capital letters next to each other are not allowed. @@ -49,7 +52,7 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed -- Nothing. +- [#51](https://github.com/webimpress/coding-standard/pull/51) fixes multiple cases when empty line before comment in array was not allowed ## 1.0.6 - TBD